|
|
|
/***************************************************************************
|
|
|
|
begin : Sun Oct 3 1999
|
|
|
|
copyright : Modifications (C) 1999 by Peter Putzer
|
|
|
|
email : putzer@kde.org
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* 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. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <glob.h>
|
|
|
|
#include <locale.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
/* Changes
|
|
|
|
2000-08-04 - Peter Putzer <putzer@kde.org>
|
|
|
|
fixed compilation on *BSD (use GLOB_NOCHECK & strcmp instead of
|
|
|
|
checking for GLOB_NOMATCH)
|
|
|
|
|
|
|
|
1999-04-11 - Peter Putzer <putzer@kde.org>
|
|
|
|
modified leveldb.h for use with C++
|
|
|
|
|
|
|
|
1998-09-22 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
|
|
|
|
i18n for init.d scripts (eg.: description(pt_BR) is a brazilian
|
|
|
|
portuguese description for the package)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define _(String) String
|
|
|
|
|
|
|
|
#include "leveldb.h"
|
|
|
|
|
|
|
|
int parseLevels(const char* str, int emptyOk) {
|
|
|
|
const char* chptr = str;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (!str || !strlen(str))
|
|
|
|
return emptyOk ? 0 : -1;
|
|
|
|
|
|
|
|
while (*chptr) {
|
|
|
|
if (!isdigit(*chptr) || *chptr > '6') return -1;
|
|
|
|
rc |= 1 << (*chptr - '0');
|
|
|
|
chptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int readServiceInfo(const char* RUNLEVELS, const char * name, struct service * service) {
|
|
|
|
char * filename = (char *) malloc(strlen(name) + strlen(RUNLEVELS) + 50);
|
|
|
|
int fd, i;
|
|
|
|
struct stat sb;
|
|
|
|
char * bufstart, * bufstop, * start, * end, * next;
|
|
|
|
struct service serv = { NULL, -1, -1, -1, NULL };
|
|
|
|
char overflow;
|
|
|
|
char english;
|
|
|
|
char is_my_lang = 0;
|
|
|
|
char levelbuf[20];
|
|
|
|
char * lang = getenv ("LANG"),
|
|
|
|
* final_parenthesis,
|
|
|
|
* english_desc = NULL;
|
|
|
|
char my_lang_loaded = 0;
|
|
|
|
|
|
|
|
sprintf(filename, "%s/init.d/%s", RUNLEVELS, name);
|
|
|
|
|
|
|
|
if ((fd = open(filename, O_RDONLY)) < 0)
|
|
|
|
{
|
|
|
|
free(filename);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free(filename);
|
|
|
|
fstat(fd, &sb);
|
|
|
|
|
|
|
|
bufstart = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
|
|
|
if (bufstart == ((caddr_t) -1)) {
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bufstop = bufstart + sb.st_size;
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
next = bufstart;
|
|
|
|
while (next < bufstop && (serv.levels == -1 || !serv.desc)) {
|
|
|
|
start = next;
|
|
|
|
|
|
|
|
while (isspace(*start) && start < bufstop) start++;
|
|
|
|
if (start == bufstop) break;
|
|
|
|
|
|
|
|
end = strchr(start, '\n');
|
|
|
|
if (!end)
|
|
|
|
next = end = bufstop;
|
|
|
|
else
|
|
|
|
next = end + 1;
|
|
|
|
|
|
|
|
if (*start != '#') continue;
|
|
|
|
|
|
|
|
start++;
|
|
|
|
while (isspace(*start) && start < end) start++;
|
|
|
|
if (start == end) continue;
|
|
|
|
|
|
|
|
if (!strncmp(start, "chtdeconfig:", 10)) {
|
|
|
|
start += 10;
|
|
|
|
while (isspace(*start) && start < end) start++;
|
|
|
|
if (start == end) {
|
|
|
|
if (serv.desc) free(serv.desc);
|
|
|
|
munmap(bufstart, sb.st_size);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sscanf(start, "%19s %d %d%c", levelbuf,
|
|
|
|
&serv.sPriority, &serv.kPriority, &overflow) != 4) ||
|
|
|
|
overflow != '\n') {
|
|
|
|
if (serv.desc) free(serv.desc);
|
|
|
|
munmap(bufstart, sb.st_size);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(levelbuf, "-"))
|
|
|
|
serv.levels = 0;
|
|
|
|
else
|
|
|
|
serv.levels = parseLevels(levelbuf, 0);
|
|
|
|
if (serv.levels == -1) {
|
|
|
|
if (serv.desc) free(serv.desc);
|
|
|
|
munmap(bufstart, sb.st_size);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else if (!strncmp(start, "description", 11)) {
|
|
|
|
start += 11;
|
|
|
|
|
|
|
|
english = *start == ':';
|
|
|
|
|
|
|
|
if (!english) {
|
|
|
|
if (*start != '(') {
|
|
|
|
if (serv.desc) free(serv.desc);
|
|
|
|
munmap(bufstart, sb.st_size);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
++start;
|
|
|
|
final_parenthesis = strchr (start, ')');
|
|
|
|
|
|
|
|
if (final_parenthesis == NULL || final_parenthesis - start > 5) {
|
|
|
|
if (serv.desc) free(serv.desc);
|
|
|
|
munmap(bufstart, sb.st_size);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
is_my_lang = lang ? strncmp (lang, start, strlen (lang)) == 0 : 0;
|
|
|
|
start = final_parenthesis + 2;
|
|
|
|
} else ++start;
|
|
|
|
|
|
|
|
while (isspace(*start) && start < end) start++;
|
|
|
|
if (start == end) {
|
|
|
|
munmap(bufstart, sb.st_size);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
char* desc = malloc(end - start + 1);
|
|
|
|
strncpy(desc, start, end - start);
|
|
|
|
desc[end - start] = '\0';
|
|
|
|
|
|
|
|
start = next;
|
|
|
|
|
|
|
|
while (desc[strlen(desc) - 1] == '\\') {
|
|
|
|
desc[strlen(desc) - 1] = '\0';
|
|
|
|
start = next;
|
|
|
|
|
|
|
|
while (isspace(*start) && start < bufstop) start++;
|
|
|
|
if (start == bufstop || *start != '#') {
|
|
|
|
munmap(bufstart, sb.st_size);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
start++;
|
|
|
|
|
|
|
|
while (isspace(*start) && start < bufstop) start++;
|
|
|
|
if (start == bufstop) {
|
|
|
|
munmap(bufstart, sb.st_size);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
end = strchr(start, '\n');
|
|
|
|
if (!end)
|
|
|
|
next = end = bufstop;
|
|
|
|
else
|
|
|
|
next = end + 1;
|
|
|
|
|
|
|
|
i = strlen(desc);
|
|
|
|
desc = realloc(desc, i + end - start + 1);
|
|
|
|
strncat(desc, start, end - start);
|
|
|
|
desc[i + end - start] = '\0';
|
|
|
|
|
|
|
|
start = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (desc) {
|
|
|
|
if (my_lang_loaded) {
|
|
|
|
free(desc);
|
|
|
|
} else if (is_my_lang) {
|
|
|
|
if (serv.desc)
|
|
|
|
free(serv.desc);
|
|
|
|
|
|
|
|
serv.desc = desc;
|
|
|
|
break;
|
|
|
|
} else if (english) {
|
|
|
|
if (serv.desc)
|
|
|
|
free(serv.desc);
|
|
|
|
|
|
|
|
if (english_desc)
|
|
|
|
free (english_desc);
|
|
|
|
|
|
|
|
english_desc = desc;
|
|
|
|
} else free (desc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
munmap(bufstart, sb.st_size);
|
|
|
|
|
|
|
|
if (!serv.desc) {
|
|
|
|
if (english_desc)
|
|
|
|
serv.desc = english_desc;
|
|
|
|
} else if (english_desc)
|
|
|
|
free (english_desc);
|
|
|
|
|
|
|
|
if ((serv.levels == -1 ) || !serv.desc) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
serv.name = strdup(name);
|
|
|
|
|
|
|
|
*service = serv;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns -1 on error */
|
|
|
|
int currentRunlevel(void) {
|
|
|
|
FILE * p;
|
|
|
|
char response[50];
|
|
|
|
|
|
|
|
p = popen("/sbin/runlevel", "r");
|
|
|
|
if (!p) return -1;
|
|
|
|
|
|
|
|
if (!fgets(response, sizeof(response), p)) {
|
|
|
|
pclose(p);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pclose(p);
|
|
|
|
|
|
|
|
if (response[1] != ' ' || !isdigit(response[2]) || response[3] != '\n')
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return response[2] - '0';
|
|
|
|
}
|
|
|
|
|
|
|
|
int findServiceEntries(const char* RUNLEVELS, const char* name, int level, glob_t * globresptr) {
|
|
|
|
char match[200];
|
|
|
|
glob_t globres;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
sprintf(match, "%s/rc%d.d/[SK][0-9][0-9]%s", RUNLEVELS, level, name);
|
|
|
|
|
|
|
|
rc = glob(match, GLOB_ERR | GLOB_NOSORT | GLOB_NOCHECK, NULL, &globres);
|
|
|
|
|
|
|
|
if (rc) {
|
|
|
|
fprintf(stderr, _("failed to glob pattern %s: %s\n"), match,
|
|
|
|
strerror(errno));
|
|
|
|
return 1;
|
|
|
|
} else if (!strcmp(match, globres.gl_pathv[0])) {
|
|
|
|
globresptr->gl_pathc = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*globresptr = globres;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int isConfigured(const char* RUNLEVELS, const char* name, int level) {
|
|
|
|
glob_t globres;
|
|
|
|
|
|
|
|
if (findServiceEntries(RUNLEVELS, name, level, &globres))
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
if (!globres.gl_pathc)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
globfree(&globres);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int isOn(const char* RUNLEVELS, const char* name, int level) {
|
|
|
|
glob_t globres;
|
|
|
|
|
|
|
|
if (level == -1) {
|
|
|
|
level = currentRunlevel();
|
|
|
|
if (level == -1) {
|
|
|
|
fprintf(stderr, _("cannot determine current run level\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (findServiceEntries(RUNLEVELS, name, level, &globres))
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
if (!globres.gl_pathc || !strstr(globres.gl_pathv[0], "/S"))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
globfree(&globres);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int doSetService(const char* RUNLEVELS, struct service s, int level, int on) {
|
|
|
|
int priority = on ? s.sPriority : s.kPriority;
|
|
|
|
char linkname[200];
|
|
|
|
char linkto[200];
|
|
|
|
glob_t globres;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!findServiceEntries(RUNLEVELS, s.name, level, &globres)) {
|
|
|
|
for (i = 0; (unsigned int) i < globres.gl_pathc; i++)
|
|
|
|
unlink(globres.gl_pathv[i]);
|
|
|
|
if (globres.gl_pathc) globfree(&globres);
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(linkname, "%s/rc%d.d/%c%02d%s", RUNLEVELS, level,
|
|
|
|
on ? 'S' : 'K', priority, s.name);
|
|
|
|
sprintf(linkto, "../init.d/%s", s.name);
|
|
|
|
|
|
|
|
unlink(linkname); /* just in case */
|
|
|
|
if (symlink(linkto, linkname)) {
|
|
|
|
fprintf(stderr, _("failed to make symlink %s: %s\n"), linkname,
|
|
|
|
strerror(errno));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|