* Problems implementing service installer in cron-2.9.3
@ 2001-05-07 23:35 Ralf Habacker
0 siblings, 0 replies; only message in thread
From: Ralf Habacker @ 2001-05-07 23:35 UTC (permalink / raw)
To: Cygwin
[-- Attachment #1: Type: text/plain, Size: 340 bytes --]
Hi,
I like to integrate a service installer in cron and have adapted the service
code from cygipc.
I can compile this stuff, install/remove the service, but starting don't
work.
Has anyone an idea, what I have done wrong ? The relating code is appended.
Regards
Ralf Habacker
EMail: Ralf@habacker.de
Ralf.Habacker@saght.tessag.com
[-- Attachment #2: cron.cc --]
[-- Type: text/x-c, Size: 11289 bytes --]
/* cron.cc - main source of cron(8)
Copyright (C) 1998 Corinna Vinschen <corinna.vinschen@cityweb.de>
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, 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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/cygwin.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <time.h>
#include <fcntl.h>
#include <process.h>
#include <windows.h>
#include <popt.h>
#include "CString.h"
#include "entry.h"
#include "crontab.h"
#include "cronPW.h"
#include "crontabList.h"
#include "service.h"
int work_main(void);
static void usage(poptContext optCon, FILE * f, char * name);
static void help(poptContext optCon, FILE * f, char * name);
static void version(poptContext optCon, FILE * f, char * name);
static void license(poptContext optCon, FILE * f, char * name);
LPSECURITY_ATTRIBUTES
NullSA (void)
{
static PSECURITY_DESCRIPTOR pSDNull;
static SECURITY_ATTRIBUTES SA;
if (!pSDNull)
{
pSDNull = (PSECURITY_DESCRIPTOR)
LocalAlloc (LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor (pSDNull, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl (pSDNull, TRUE, NULL, FALSE);
}
SA.nLength = sizeof SA;
SA.lpSecurityDescriptor = pSDNull; // Security-Descriptor mit leerer ACL
SA.bInheritHandle = TRUE; // Handle wird an Subprozesse vererbt
return &SA;
}
int
OpenCronFile (const char *name)
{
return open(name, O_CREAT | O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR);
}
bool
WriteTimeStamp (int fdOut, int fdErr)
{
time_t t = time ((time_t *) 0);
write (fdOut, "\ncron: ", 7);
write (fdOut, ctime (&t), 25);
write (fdErr, "\ncron: ", 7);
write (fdErr, ctime (&t), 25);
return false;
}
void
WriteError (int fdErr, const char *text)
{
DWORD written;
CString ErrTxt;
ErrTxt.Format ("%d\n", GetLastError ());
write (fdErr, text, strlen (text));
write (fdErr, ": ", 2);
write (fdErr, ErrTxt, ErrTxt.GetLength ());
}
LPSTARTUPINFO
StartupInfo (int fdOut, int fdErr)
{
static STARTUPINFO si;
memset (&si, 0, sizeof si);
si.cb = sizeof si;
si.dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES;
si.hStdOutput = (HANDLE) get_osfhandle (fdOut);
si.hStdError = (HANDLE) get_osfhandle (fdErr);
return &si;
}
time_t
WaitForNextMinute (time_t last)
{
time_t now;
do
{
Sleep (5000L);
now = time ((time_t *) 0);
}
while (now / 60 == last / 60);
return now;
}
HANDLE
CreateUserToken (const char *user, const char *pwd, int fdOut, int fdErr)
{
HANDLE hUser;
if (! LogonUser ((char *) user, ".", (char *) pwd,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&hUser))
{
WriteTimeStamp (fdOut, fdErr);
WriteError (fdErr, "LogonUser");
return NULL;
}
return hUser;
}
int
main (int argc, char **argv)
{
char *myname;
int install = 0, remove = 0;
poptContext optCon;
const char ** rest;
int rc;
int ec = 0;
int c;
int debug = 0;
struct poptOption generalOptionsTable[] = {
{ "quiet", 'q', POPT_ARG_NONE, NULL, 'q', \
"Quiet mode", NULL},
{ "install-as-service", '\0', POPT_ARG_NONE, NULL, 'I', \
"Install as a windows service.", NULL},
{ "remove-as-service", '\0', POPT_ARG_NONE, NULL, 'R', \
"Remove as a windows service.", NULL},
{ "service", 's', POPT_ARG_NONE, NULL, 's', \
"Run in service mode. This option should ONLY be used "
"from within the NT/2K service manager system; do NOT "
"use it in ANY other context -- shortcuts, .bat files, "
"manual command-line entry, etc.", NULL},
{ "debug", 'd', POPT_ARG_NONE, NULL, 'd', \
"Print execution trace to stderr (or syslog if in service mode)", NULL},
{ NULL, '\0', 0, NULL, 0, NULL, NULL }
};
struct poptOption helpOptionsTable[] = {
{ "help", '?', POPT_ARG_NONE, NULL, '?', \
"Show this help message", NULL},
{ "usage", '\0', POPT_ARG_NONE, NULL, 'u', \
"Display brief usage message", NULL},
{ "version", '\0', POPT_ARG_NONE, NULL, 'v', \
"Display version information", NULL},
{ "license", '\0', POPT_ARG_NONE, NULL, 'l', \
"Display licensing information", NULL},
{ NULL, '\0', 0, NULL, 0, NULL, NULL }
};
struct poptOption opt[] = {
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, generalOptionsTable, 0, \
"General options", NULL },
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, helpOptionsTable, 0, \
"Help options", NULL },
{ NULL, '\0', 0, NULL, 0, NULL, NULL }
};
if (! (myname = strrchr (argv[0], '\\'))
&& ! (myname = strrchr (argv[0], '/')))
myname = argv[0];
else
++myname;
if (strrchr (myname, '.'))
*strrchr (myname, '.') = '\0';
optCon = poptGetContext(NULL, argc, (const char **) argv, opt, 0);
while ((rc = poptGetNextOpt(optCon)) > 0) {
switch (rc) {
case '?': help(optCon, stderr, myname);
goto exit;
case 'v': version(optCon, stderr, myname);
goto exit;
case 'l': license(optCon, stderr, myname);
goto exit;
case 'd': debug = 1;
break;
case 'I': install = 1;
break;
case 'R': remove = 1;
break;
case 's': service = 1;
break;
default: usage(optCon, stderr, myname);
goto exit;
}
}
/*
if (rc < -1 ) {
log_message(stderr, LOG_ERR, "%s: bad argument %s: %s",myname, poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
poptStrerror(rc));
ec = 2;
goto exit;
}
if (install && remove) {
log_message(stderr, LOG_ERR,
"%s: can't specify both --install-as-service and --remove-as-service\nNo action taken.", myname);
ec = 2;
goto exit;
}
*/
rest = poptGetArgs(optCon);
if (rest) {
char buf[2000];
int count;
count = snprintf(buf, 2000, "Extra args ignored: ");
while (*rest)
count += snprintf(buf + count, 2000 - count, "%s ", *rest++);
// log_message(stderr, LOG_WARNING, buf);
}
if (!debug && !install && !remove && !service)
switch (pid_t pid = fork ())
{
case -1:
perror (myname);
return 1;
case 0:
close (0);
close (1);
close (2);
setsid ();
break;
default:
return 0;
}
// install cron as service
if (install) {
ec = install_as_service(myname, 1);
if (!ec) {
ec = install_reg_entries(myname, 1);
if (ec)
remove_as_service(myname, 1);
}
}
else if (remove) {
ec = remove_as_service(myname, 1);
}
else if (service) {
ec = start_service();
}
else {
work_main();
ec = 0;
}
exit:
poptFreeContext(optCon);
// closelog();
return(ec);
}
int work_main(void)
{
CCrontabList cronlist;
time_t now = time ((time_t *) 0);
while (now = WaitForNextMinute (now))
{
CLEntry *listentry;
CEntry *entry;
cronlist.Open (GetCronDir ());
while (listentry = cronlist.NextEntry ())
{
bool first = true;
int fdStdOut = OpenCronFile (listentry->home + "/.cron.stdout");
int fdStdErr = OpenCronFile (listentry->home + "/.cron.stderr");
while (entry = listentry->crontab.NextEntry ())
if (*entry == now)
{
if (first)
first = WriteTimeStamp (fdStdOut, fdStdErr);
switch (pid_t pid = fork ())
{
case -1: // Error
WriteError (fdStdErr, "error invoking fork");
break;
case 0: // Child
HANDLE hUser;
int pd[2];
putenv ("LOGNAME=" + listentry->user);
putenv ("USER=" + listentry->user);
putenv ("HOME=" + listentry->home);
putenv (CString ("PATH=/bin:/usr/bin:") + getenv ("PATH"));
putenv ("SHELL=/bin/sh");
if (pipe (pd))
{
WriteError (fdStdErr, "error creating pipe");
exit (1);
}
dup2 (fdStdOut, 1);
dup2 (fdStdErr, 2);
chdir (listentry->home);
switch (fork ())
{
case -1: // Error
WriteError (fdStdErr, "error invoking fork (2)");
break;
case 0: // Child
dup2 (pd[0], 0);
close (pd[0]);
close (pd[1]);
if ((hUser = CreateUserToken (listentry->user,
cronlist.GetPwd (listentry->user),
fdStdOut,
fdStdErr)) == INVALID_HANDLE_VALUE)
exit (1);
sexecl (hUser,
"/bin/sh", "sh",
"-c", entry->cmd.c_str (),
NULL);
WriteError (fdStdErr, "error invoking sexecl");
break;
default: // Parent
close (pd[0]);
if (! entry->std_in.IsEmpty ())
write (pd[1], entry->std_in,
entry->std_in.GetLength ());
close (pd[1]);
break;
}
return 0;
/*NOTREACHED*/
default: // Parent
waitpid (pid, NULL, 0);
break;
}
}
close (fdStdOut);
close (fdStdErr);
}
}
cronlist.Close ();
}
static void printTopDescription(FILE * f, char * name)
{
char buf[512];
fprintf(f, "%s : Cygwin Cron Version %s (c) 1998 PCH/LLA, Changes (c) 2001 CSW\n",
name, getVersion(buf, 512));
fprintf(f, " This daemon provides crontab functionality.\n\n");
}
static void printLicense(FILE * f, char * name)
{
fprintf(f, "This program is free software; you can redistribute it and/or\n");
fprintf(f, "modify it under the terms of the GNU General Public License\n");
fprintf(f, "as published by the Free Software Foundation; either version 2\n");
fprintf(f, "of the License, or (at your option) any later version.\n");
fprintf(f, "\n");
fprintf(f, "This program is distributed in the hope that it will be useful,\n");
fprintf(f, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
fprintf(f, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
fprintf(f, "GNU General Public License for more details.\n");
fprintf(f, "\n");
fprintf(f, "You should have received a copy of the GNU General Public License\n");
fprintf(f, "along with this program; if not, write to the Free Software\n");
fprintf(f, "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n");
fprintf(f, "\n");
fprintf(f, "See the COPYING file for license information.\n");
}
static void usage(poptContext optCon, FILE * f, char * name)
{
poptPrintUsage(optCon, f, 0);
}
static void help(poptContext optCon, FILE * f, char * name)
{
printTopDescription(f, name);
poptPrintHelp(optCon, f, 0);
}
static void version(poptContext optCon, FILE * f, char * name)
{
printTopDescription(f, name);
}
static void license(poptContext optCon, FILE * f, char * name)
{
printTopDescription(f, name);
printLicense(f, name);
}
[-- Attachment #3: Makefile --]
[-- Type: text/x-makefile, Size: 3562 bytes --]
# Makefile - Makefile for cron
# Copyright (C) 1998 Corinna Vinschen <corinna.vinschen@cityweb.de>
#
# 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, 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#
# current version of cron
#
VERSION= 2.9.3
#
# The following three settings affect the local security.
# Change them, to use your own local settings and don't tell about!
#
# PWBUFSIZ should be greater than 128.
#
# PWBUFPOS should be greater than 32 and less than PWBUFPOS - 32.
#
# PWKEYWORD should be exactly 8 characters long.
#
# PWBUFSIZ= -DPWBUFSIZ=500
# PWBUFPOS= -DPWBUFPOS=238
# PWKEYWORD= -DPWKEYWORD="\"\340\221\172\033\061\105\304\057\""
#
PWBUFSIZ= -DPWBUFSIZ=512
PWBUFPOS= -DPWBUFPOS=256
PWKEYWORD= -DPWKEYWORD="\"\107\056\114\273\146\231\033\266\""
EXEEXT=.exe
#EXEEXT=
PREFIX=/usr/local
BINDIR=$(PREFIX)/bin
SBINDIR=$(PREFIX)/sbin
MANDIR=$(PREFIX)/man
CRONDIR=/var/cron
CXX=g++ -g
CXXFLAGS=$(PWBUFSIZ) $(PWBUFPOS) $(PWKEYWORD)
LDFLAGS=
LIBS=-L/usr/lib -lpopt
COMMONOBJ= CString.o \
cronPW.o \
crontab.o \
crontabList.o \
entry.o
CRYPTOBJ= encrypt.o
CRONOBJ= cron.o service.o $(COMMONOBJ) $(CRYPTOBJ)
CRONTABOBJ= crontabApp.o $(COMMONOBJ) $(CRYPTOBJ)
all: cron$(EXEEXT) crontab$(EXEEXT)
cron$(EXEEXT): $(CRONOBJ)
$(CXX) $(LDFLAGS) -o $@ $(CRONOBJ) $(LIBS)
crontab$(EXEEXT): $(CRONTABOBJ)
$(CXX) $(LDFLAGS) -o $@ $(CRONTABOBJ) -lnetapi32
cronPW.o: encrypt.h
cron.o crontabList.o: crontabList.h
cron.o crontabApp.o crontabList.o cronPW.o: cronPW.h
cron.o crontabApp.o crontabList.o crontab.o: crontab.h
cron.o crontabApp.o crontabList.o crontab.o entry.o: entry.h
cron.o crontabApp.o $(COMMONOBJ): CString.h Makefile
install: $(SBINDIR)/cron.exe $(BINDIR)/crontab$(EXEEXT)
if [ ! -d $(CRONDIR) ]; then \
mkdir $(CRONDIR); \
cp deny $(CRONDIR); \
fi
#Don't use $(EXEEXT) here!
$(SBINDIR)/cron.exe: cron$(EXEEXT)
cp cron$(EXEEXT) $@
-chmod 775 $@
$(BINDIR)/crontab$(EXEEXT): crontab$(EXEEXT)
cp crontab$(EXEEXT) $@
-chmod 775 $@
docinstall: $(MANDIR)/man1/crontab.1 $(MANDIR)/man5/crontab.5 $(MANDIR)/man8/cron.8
$(MANDIR)/man1/crontab.1:
cp crontab.1 $(MANDIR)/man1
-chmod 664 $@
$(MANDIR)/man5/crontab.5:
cp crontab.5 $(MANDIR)/man5
-chmod 664 $@
$(MANDIR)/man8/cron.8:
cp cron.8 $(MANDIR)/man8
-chmod 664 $@
clean:
-rm -f cron$(EXEEXT) crontab$(EXEEXT) *.o *.core *.tar.gz
archive: cron-$(VERSION).src.tar.gz cron-$(VERSION).bin.tar.gz
ARCLIST= cron-$(VERSION)/COPYING \
cron-$(VERSION)/ChangeLog \
cron-$(VERSION)/Makefile \
cron-$(VERSION)/*.c \
cron-$(VERSION)/*.cc \
cron-$(VERSION)/*.h \
cron-$(VERSION)/*.[158] \
cron-$(VERSION)/deny
cron-$(VERSION).src.tar.gz: Makefile
cd ..; tar czf cron-$(VERSION)/$@ $(ARCLIST)
BINARCLIST= $(SBINDIR)/cron$(EXEEXT) \
$(BINDIR)/crontab$(EXEEXT) \
$(MANDIR)/man1/crontab.1 \
$(MANDIR)/man5/crontab.5 \
$(MANDIR)/man8/cron.8 \
$(CRONDIR)/deny
cron-$(VERSION).bin.tar.gz: Makefile $(BINARCLIST)
tar czf $@ $(BINARCLIST)
[-- Attachment #4: service.cc --]
[-- Type: text/x-c, Size: 14457 bytes --]
/* $Id: ip-daemon.c,v 1.14 2001/02/16 16:15:07 cwilson Exp $ */
/*
* service installer
*
* Copyright (C) 1997 Philippe CHAPUY
* Copyright (C) 1998 Ludovic LANGE
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* HISTORY:
* --------
*
* 13/05/1998 : Version 1.00 released
* First public release
* adress any comments to llange@capgemini.fr
*
*/
/*
* About fprintf, syslog, and log_message:
* if a message needs to be sent to the user, then use these
* functions under the following circumstances:
* - fprintf: stuff that is immediately user-interactive
* e.g. you don't want to see "help instructions"
* in the syslog.
* - syslog: when the block of code is only reachable
* when running as a service --- but, for simplicity,
* we just use log_message anyway.
* - log_message: when the block of code could be reached
* when running as a service OR standalone
*/
/************************************************************************/
/* */
/************************************************************************/
//#define EXTERN
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <stdarg.h>
#include <windows.h>
#include <exceptions.h>
#include <sys/cygwin.h>
#include <sys/wait.h>
#include <syslog.h>
#include "service.h"
int work_main(void);
char * getVersion(char * buf, int len);
static void get_null_sa (SECURITY_ATTRIBUTES *sap);
int get_reg_entries(void);
int log_message(FILE *stream, int severity, const char *fmt, ...);
char verbose=1;
int service=0;
char tight_security=0;
char debug=0;
#define is_winnt (GetVersion() < 0x80000000)
#define CROND_SERVICE_NAME "cron-daemon1"
#define CROND_SERVICE_DISPLAY "Cron Daemon"
#define CROND_PARAM_KEY "SYSTEM\\CurrentControlSet\\Services\\" \
CROND_SERVICE_NAME \
"\\Parameters"
#define CROND_PARAM_SECURITY "TightSecurity"
#define CROND_PARAM_DEBUG "Debug"
int server_pid = 0;
SERVICE_STATUS_HANDLE ssh;
SERVICE_STATUS ss;
HANDLE hStopEvent = NULL;
int install_reg_entries(const char *myname, int verbose)
{
HKEY srv_key = NULL;
DWORD disp;
DWORD temp;
char *err_func;
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, CROND_PARAM_KEY, 0, "",
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
NULL, &srv_key, &disp)
!= ERROR_SUCCESS)
{
err_func = "RegCreateKeyEx";
goto error;
}
temp = tight_security;
if (RegSetValueEx(srv_key, CROND_PARAM_SECURITY, 0, REG_DWORD,
(CONST BYTE *) &temp, sizeof(DWORD))
!= ERROR_SUCCESS)
{
err_func = "RegSetValueEx(TightSecurity=1)";
goto error;
}
temp = debug;
if (RegSetValueEx(srv_key, CROND_PARAM_DEBUG, 0, REG_DWORD,
(CONST BYTE *) &temp, sizeof(DWORD))
!= ERROR_SUCCESS)
{
err_func = "RegSetValueEx(Debug=1)";
goto error;
}
RegFlushKey(srv_key);
RegCloseKey(srv_key);
return 0;
error:
if (srv_key)
RegCloseKey(srv_key);
if (verbose)
log_message(stderr, LOG_ERR, "%s: %ld = %s()\n",
myname, GetLastError(), err_func);
log_message(stderr, LOG_ERR,
"%s: installing registry entries for `cron-daemon' failed\n",
myname);
return 1;
}
int get_reg_entries(void)
{
HKEY srv_key = NULL;
DWORD type, size;
DWORD tight_security_temp;
DWORD debug_temp;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, CROND_PARAM_KEY, 0,
KEY_ALL_ACCESS, &srv_key)
!= ERROR_SUCCESS)
{
log_message(stderr, LOG_WARNING,
"couldn't get parameters from registry, using defaults\n"
"error %ld in RegOpenKeyEx()", GetLastError());
return 1;
}
if (RegQueryValueEx(srv_key, CROND_PARAM_DEBUG, 0, &type,
(unsigned char *) &debug_temp, (size = sizeof(DWORD), &size))
!= ERROR_SUCCESS)
log_message(stderr, LOG_WARNING,
"couldn't get debug value from registry, "
"using default value %d", debug);
else {
debug = (char) debug_temp;
log_message(stderr, LOG_DEBUG, "debug value: %d", debug);
}
if (RegQueryValueEx(srv_key, CROND_PARAM_SECURITY, 0, &type,
(unsigned char *) &tight_security_temp, (size = sizeof(DWORD), &size))
!= ERROR_SUCCESS)
log_message(stderr, LOG_WARNING,
"couldn't get tight_security boolean from registry, "
"using default value %d", tight_security);
else {
tight_security = (char) tight_security_temp;
log_message(stderr, LOG_DEBUG, "tight_security value: %d", tight_security);
}
RegCloseKey(srv_key);
return 0;
}
VOID WINAPI
service_handler(DWORD ctrl)
{
exception_list except_list;
cygwin_internal (CW_INIT_EXCEPTIONS, &except_list);
switch (ctrl) {
case SERVICE_CONTROL_STOP:
ss.dwCheckPoint = 1;
ss.dwWaitHint = 3000L; // wait up to 3 seconds...
ss.dwCurrentState = SERVICE_STOP_PENDING;
if (hStopEvent) {
log_message(stderr, LOG_INFO, "sending hStopEvent");
SetEvent(hStopEvent);
}
else
log_message(stderr, LOG_INFO, "no hStopEvent to send");
break;
default:
// ignore
break;
}
SetServiceStatus(ssh, &ss);
}
void WINAPI
service_main(DWORD argc, LPSTR *argv)
{
exception_list except_list;
cygwin_internal (CW_INIT_EXCEPTIONS, &except_list);
// Initialized Cygwin exception handling for thread not
// created by Cygwin.
if (! (ssh = RegisterServiceCtrlHandlerA(CROND_SERVICE_NAME,
service_handler))) {
log_message(stderr, LOG_ERR,
"error in service_main: %d = RegSrvCtrlHandler()",
GetLastError());
log_message(stderr, LOG_ERR, "starting 'cron-daemon' as a service failed");
return;
}
ss.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
ss.dwCurrentState = SERVICE_START_PENDING;
ss.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ss.dwWin32ExitCode = NO_ERROR;
ss.dwCheckPoint = 1;
ss.dwWaitHint = 3000L;
SetServiceStatus(ssh, &ss);
get_reg_entries();
log_message(stderr, LOG_DEBUG, "service: %d, debug %d, tight_security %d",
service, debug, tight_security);
work_main();
log_message(stderr, LOG_INFO, "'cron-daemon' service stopped");
ss.dwCheckPoint = 0;
ss.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(ssh, &ss);
}
int
install_as_service(const char *myname, int verbose)
{
char mypath[MAX_PATH+5];
char *err_func;
SC_HANDLE sm = (SC_HANDLE) 0;
SC_HANDLE sh = (SC_HANDLE) 0;
SC_LOCK sl = (SC_LOCK) 0;
// get own full path name
if (! GetModuleFileName(NULL, mypath, MAX_PATH))
{
err_func = "GetModuleFileName";
goto error;
}
// we can't read parameters from registry unless we
// already know we are a service. So, appname must include
// --service option:
strcat(mypath, " \"--service\"");
// open service manager database
if (! (sm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)))
{
err_func = "OpenSCManager";
goto error;
}
// lock service database
if (! (sl = LockServiceDatabase(sm)))
{
err_func = "LockServiceDatabase";
goto error;
}
// open service, go ahead if service doesn't exists
if (! (sh = OpenService(sm, CROND_SERVICE_NAME, SERVICE_ALL_ACCESS)) &&
GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
{
err_func = "OpenService";
goto error;
}
// service already exists
if (sh)
{
if (verbose)
log_message(stderr, LOG_WARNING, "%s: service already installed", myname);
}
// no, create service
else if (! (sh = CreateService(sm,
CROND_SERVICE_NAME,
CROND_SERVICE_DISPLAY,
STANDARD_RIGHTS_REQUIRED |
SERVICE_INTERROGATE |
SERVICE_QUERY_STATUS |
SERVICE_START |
SERVICE_STOP,
SERVICE_WIN32_OWN_PROCESS /*|
SERVICE_INTERACTIVE_PROCESS*/,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
mypath,
NULL,
NULL,
NULL,
NULL,
NULL
)))
{
err_func = "CreateService";
goto error;
}
// if CloseServiceHandle returns with error, it's not sure
// whether anything works...
if (! CloseServiceHandle(sh))
{
err_func = "CloseServiceHandle";
goto error;
}
return 0;
error:
if (verbose)
log_message(stderr, LOG_ERR, "%s: %lu = %s()",
myname, GetLastError(), err_func);
log_message(stderr, LOG_ERR, "%s: installing service `cron-daemon' failed", myname);
if (sh)
CloseServiceHandle(sh);
if (sl && ! UnlockServiceDatabase(sl))
log_message(stderr, LOG_WARNING,
"%s: CAUTION: UnlockServiceDatabase() failed "
"with error %lu", myname, GetLastError());
return 1;
}
int
remove_as_service(const char *myname, int verbose)
{
char *err_func;
SC_HANDLE sm = (SC_HANDLE) 0;
SC_HANDLE sh = (SC_HANDLE) 0;
SC_LOCK sl = (SC_LOCK) 0;
SERVICE_STATUS ss;
int err;
// open service manager database
if (! (sm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)))
{
err_func = "OpenSCManager";
goto error;
}
// lock service database
if (! (sl = LockServiceDatabase(sm)))
{
err_func = "LockServiceDatabase";
goto error;
}
// check whether service exists
if (! (sh = OpenService(sm, CROND_SERVICE_NAME, SERVICE_ALL_ACCESS)))
{
if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
{
if (verbose)
log_message(stderr, LOG_ERR, "%s: service isn't installed", myname);
if (! UnlockServiceDatabase(sl))
log_message(stderr, LOG_WARNING,
"%s: CAUTION: UnlockServiceDatabase() failed "
"with error %lu", myname, GetLastError());
return 0;
}
err_func = "OpenService";
goto error;
}
// try stopping service
// if NOT_ACTIVE or CANNOT_ACCEPT_CTRL go ahead, else exit
if (! ControlService(sh, SERVICE_CONTROL_STOP, &ss) &&
(err = GetLastError()) != ERROR_SERVICE_NOT_ACTIVE &&
err != ERROR_SERVICE_CANNOT_ACCEPT_CTRL)
{
err_func = "ControlService";
goto error;
}
// wait, 'til service is stopped
do
{
sleep(1);
if (! QueryServiceStatus(sh, &ss))
{
err_func = "QueryServiceStatus";
goto error;
}
}
while (ss.dwCurrentState != SERVICE_STOPPED);
// remove service
if (! DeleteService(sh))
{
err_func = "DeleteService";
goto error;
}
// if CloseServiceHandle returns with error, it's not sure
// whether anything works...
if (! CloseServiceHandle(sh))
{
sh = (SC_HANDLE) 0;
err_func = "CloseServiceHandle";
goto error;
}
sh = (SC_HANDLE) 0;
// Datenbank-Lock aufheben
if (sl && ! UnlockServiceDatabase(sl))
{
log_message(stderr, LOG_WARNING,
"%s: CAUTION: UnlockServiceDatabase() failed "
"with error %lu", myname, GetLastError());
}
return 0;
error:
if (verbose)
log_message(stderr, LOG_ERR, "%s: %lu = %s()",
myname, GetLastError(), err_func);
log_message(stderr, LOG_ERR, "%s: removing `cron-daemon' as service failed", myname);
if (sh)
CloseServiceHandle(sh);
if (sl && ! UnlockServiceDatabase(sl))
fprintf(stderr,
"%s: CAUTION: UnlockServiceDatabase() failed "
"with error %lu", myname, GetLastError());
return 1;
}
//
// start service
//
//
int start_service(void)
{
SERVICE_TABLE_ENTRYA ste[2];
ste[0].lpServiceName = CROND_SERVICE_NAME;
ste[0].lpServiceProc = service_main;
ste[1].lpServiceName = NULL;
ste[1].lpServiceProc = NULL;
StartServiceCtrlDispatcherA(ste);
return 0;
}
char * getVersion(char * buf, int len)
{
unsigned short LVersionMajor=1;
unsigned short LVersionMinor=0;
// LVersionMajor=(unsigned short)VERSION_NUM;
// LVersionMinor=(unsigned short)( (VERSION_NUM-LVersionMajor)*100 );
snprintf(buf, len, "%d.%02d", LVersionMajor, LVersionMinor);
return buf;
}
static void get_null_sa (LPSECURITY_ATTRIBUTES sap)
{
static SECURITY_DESCRIPTOR *null_sdp = 0;
static SECURITY_DESCRIPTOR sd;
if (!sap)
return;
if (!null_sdp)
{
InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE);
null_sdp = &sd;
}
sap->nLength = sizeof *sap;
sap->lpSecurityDescriptor = null_sdp;
sap->bInheritHandle = TRUE;
}
int log_message(FILE *stream, int severity, const char *fmt, ...)
{
char buf[2000];
va_list ap;
int count;
if( (debug) || (severity < LOG_DEBUG))
{
count = snprintf (buf, 2000, "(cron-daemon) ");
va_start (ap, fmt);
count += vsnprintf (buf + count, 2000 - count, fmt, ap);
va_end (ap);
if(service)
syslog(severity, buf);
else
{
snprintf(buf + count, 2000 - count, "\n");
fprintf(stream, buf);
}
}
return 0;
}
[-- Attachment #5: service.h --]
[-- Type: text/x-c, Size: 338 bytes --]
#ifndef __SERVICE_H
#define __SERVICE_H
int install_reg_entries(const char *myname, int verbose);
int install_as_service(const char *myname, int verbose);
int remove_as_service(const char *myname, int verbose);
int start_service(void);
char * getVersion(char * buf, int len);
// show active service state
extern int service;
#endif
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2001-05-07 23:35 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-05-07 23:35 Problems implementing service installer in cron-2.9.3 Ralf Habacker
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).