blob: f46312ddaf4f77c4d7573aec319b1e74668cc92f [file] [log] [blame] [raw]
/* service - toolbox
Copyright 2015-2016 Rivoreo
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
#ifdef _WIN32
#ifdef _WIN32_WCE
#include "service.wce.c"
#else
#error "Not implemented"
#endif
#else
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <getopt.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/wait.h>
#include <fcntl.h>
#define INIT_D_PATH "/etc/init.d/"
static const char *env_names[] = {
"LANG", "PATH", "TERM"
};
static const char *ignore_names[] = {
"skeleton", "README", "rc", "rcS", "single", "reboot", "bootclean.sh", "halt", "killall", "single", "linuxconf", "kudzu"
};
static char service_script[PATH_MAX+1] = INIT_D_PATH;
static size_t name_len;
static char *env[sizeof env_names / sizeof(char *) + 1];
static void print_usage(const char *name) {
fprintf(stderr, "Usage: %s { <service> [<action>] [<options>] | --status-all }\n", name);
}
static int get_status(const char *pathname) {
pid_t pid = fork();
if(pid < 0) return '?';
if(pid) {
int status;
if(waitpid(pid, &status, 0) < 0) return '?';
if(WIFSIGNALED(status)) return '?';
//fprintf(stderr, "%d\n", WEXITSTATUS(status));
int e = WEXITSTATUS(status);
if(e < 0 || e > 1) return '?';
return e == 0 ? '+' : '-';
} else {
close(STDOUT_FILENO);
close(STDERR_FILENO);
if(open("/dev/null", O_WRONLY) == STDOUT_FILENO) dup2(STDOUT_FILENO, STDERR_FILENO);
execle(pathname, pathname, "status", NULL, env);
exit(1);
}
}
static int status_all() {
struct dirent *de;
struct stat s;
DIR *d = opendir(INIT_D_PATH);
int i;
if(!d) {
perror(INIT_D_PATH);
return 1;
}
first_loop:
while((de = readdir(d))) {
if((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..") == 0)) continue;
for(i = 0; i < sizeof ignore_names / sizeof(char *); i++) {
if(strcmp(de->d_name, ignore_names[i]) == 0) goto first_loop;
}
//snprintf(tmp, sizeof(tmp), INIT_D_PATH "%s", de->d_name);
//strcpy(service_script, INIT_D_PATH);
//strcat(service_script, de->d_name);
name_len = strlen(de->d_name);
if(sizeof INIT_D_PATH + name_len > sizeof service_script) {
continue;
}
memcpy(service_script + sizeof INIT_D_PATH - 1, de->d_name, name_len + 1);
if(stat(service_script, &s) < 0) {
fprintf(stderr, "stat %s failed: %s", service_script, strerror(errno));
return 1;
}
if(!S_ISDIR(s.st_mode) && (s.st_mode & 0111)) {
//if(access(tmp, X_OK) == 0)
// fprintf(stdout, "%s\n", de->d_name);
printf(" [ %c ] %s\n", get_status(service_script), de->d_name);
}
}
return 0;
}
static void init_env() {
int i;
char **p = env;
/* How many options the env_names have. */
for(i = 0; i < sizeof env_names / sizeof(char *); i++) {
char *e = getenv(env_names[i]);
if(e) {
size_t name_len = strlen(env_names[i]);
size_t value_len = strlen(e);
*p = malloc(name_len + 1 + value_len + 1);
if(!*p) {
perror(NULL);
exit(2);
}
memcpy(*p, env_names[i], name_len);
(*p)[name_len] = '=';
memcpy(*p + name_len + 1, e, value_len + 1);
p++;
}
}
*p = NULL;
}
int service_main(int argc, char **argv) {
static struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
{ "status-all", no_argument, 0, 0 },
{ 0, 0, 0, 0 }
};
while(1) {
int option_index = 0;
int c = getopt_long(argc, argv, "h", long_options, &option_index);
if(c == -1) break;
switch(c) {
case 'h':
print_usage(argv[0]);
return 0;
case 0:
//printf("%s\n", long_options[option_index].name);
if(option_index == 1) {
init_env();
return status_all();
}
break;
case '?':
return -1;
default:
print_usage(argv[0]);
return -1;
}
}
/* Check if no option, Avoid Segmentation fault */
if(optind == argc) {
print_usage(argv[0]);
return -1;
}
name_len = strlen(argv[1]);
if(sizeof INIT_D_PATH + name_len > sizeof service_script) {
fprintf(stderr, "%s: Service name too long\n", argv[0]);
return 1;
}
memcpy(service_script + sizeof INIT_D_PATH - 1, argv[1], name_len + 1);
if(access(service_script, X_OK) < 0) {
fprintf(stderr, "%s: %s: Unrecognized service\n", argv[0], argv[1]);
return 1;
}
init_env();
//execle(service_script, argv[0], argv[2], NULL, env);
//perror(argv[1]);
argv++;
execve(service_script, argv, env);
perror(argv[0]);
return 1;
}
#endif