public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* 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).