Code Examples


These sections contain code examples to illustrate the migration techniques:

  • Test Client for Interix Daemon

  • Example Interix Daemon Code

  • Example Interix Service

Test Client for Interix Daemon

The program used to test the example daemon ( msg ) is as follows :

 $ cat msg.c #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_TEXT 512 struct my_msg_st {     long int my_msg_type;     char some_text[MAX_TEXT]; }; int main() {     int running = 1;     struct my_msg_st some_data;     int out_msgid, in_msgid;     long int msg_to_receive = 0;     char buffer[BUFSIZ]; /* First, connect to the input message queue. */     in_msgid = msgget((key_t)1235, 0666);     if (in_msgid == -1) {         fprintf(stderr, "msgget failed with error: %d\n", errno);         exit(EXIT_FAILURE);     } /* Next, connect to the output message queue. */     out_msgid = msgget((key_t)1234, 0666);     if (out_msgid == -1) {         fprintf(stderr, "msgget failed with error: %d\n", errno);         exit(EXIT_FAILURE);     }     while(running) {         printf("Enter some text: ");         fgets(buffer, BUFSIZ, stdin);         some_data.my_msg_type = 1;         strcpy(some_data.some_text, buffer);         if (msgsnd(out_msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {             fprintf(stderr, "msgsnd failed\n");             exit(EXIT_FAILURE);         }         if (msgrcv(in_msgid, (void *)&some_data, BUFSIZ,                    msg_to_receive, 0) == -1) {             fprintf(stderr, "msgrcv failed with error: %d\n", errno);             exit(EXIT_FAILURE);         }         printf("msgd received: %s", some_data.some_text);         if (strncmp(buffer, "end", 3) == 0) {             running = 0;         }     }     exit(EXIT_SUCCESS); } 

Example Interix Daemon Code

The following example daemon provides an ASCII character conversion serviceby using one System V (IPC) message queue for input and one for output. It waits for input on the input message queue (1234), converts all lowercase ASCII characters to uppercase, and returns the result to the output message queue (1235).

 $ cat msgd.c #include <signal.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_TEXT 512     int in_msgid, out_msgid; /* This function reacts to the signal which is passed in the parameter sig.     This function is called when a signal occurs.     This signal is "normally" received during a system shutdown,     and this is where cleanup is performed.     In this case the Input and Output message queues are deleted. */  void terminate(int sig) { /*  Close the input message queue */      if (msgctl(in_msgid, IPC_RMID, 0) == -1)     fprintf(stderr, "msgctl failed (input queue) error: %s\n", strerror(errno)); /*  Close the output message queue */     if (msgctl(out_msgid, IPC_RMID, 0) == -1)     fprintf(stderr, "msgctl failed (output queue) error: %s\n", strerror(errno));     exit(0); } struct my_msg_st {     long int my_msg_type;     char some_text[BUFSIZ]; }; /*  The main daemon function must intercept the SIGTERM signal generated     for example when the system shuts down.     Otherwise, it sits in an infinite loop, waiting for messages to process     on its input queue */ int main() {     pid_t pid, sessionID;     int i;     int running = 1;     struct my_msg_st some_data;     long int msg_to_receive = 0;     struct msqid_ds buf;     (void) signal(SIGTERM, terminate);     pid = fork();     switch(pid)     {     case -1:         fprintf(stderr, "fork failed");         exit(EXIT_FAILURE);     case 0: /* This is the child...so it continues on */ /* Now the child becomes the process group leader    In general, setsid only fails if the child (i.e. the calling process)    is already a process group leader. */         sessionID = setsid();         if (sessionID == -1) {             fprintf(stderr, "setsid failed");             exit(EXIT_FAILURE);         }   /* First, set up the input message queue. */         in_msgid = msgget((key_t)1234, 0666  IPC_CREAT  IPC_EXCL);         if (in_msgid == -1) {             fprintf(stderr, "msgget failed err: %s for input queue\n", strerror(errno));             exit(EXIT_FAILURE);         }     if (msgctl(in_msgid, IPC_STAT, &buf) != -1)         printf("Input Queue Permissions are: %o\n", buf.msg_perm.mode); /* Second, set up the output message queue. */         out_msgid = msgget((key_t)1235, 0666  IPC_CREAT  IPC_EXCL);         if (out_msgid == -1) {             fprintf(stderr, "msgget failed err: %s for output queue\n", strerror(errno));             exit(EXIT_FAILURE);         }         if (msgctl(out_msgid, IPC_STAT, &buf) != -1)         printf("Output Queue Permissions are: %o\n", buf.msg_perm.mode); /* Then the messages are retrieved from the input queue, converted, and sent    to the output queue, until an end message is encountered.  */         while(running) {             if (msgrcv(in_msgid, (void *)&some_data, BUFSIZ,                     msg_to_receive, 0) == -1) {         if (errno != EINTR) {             fprintf(stderr, "msgrcv failed with error: %s\n", strerror(errno));                     exit(EXIT_FAILURE);         }         else             continue;             } /*            printf("You wrote: %s", some_data.some_text); */           i=0;             while(some_data.some_text[i])                  some_data.some_text[i++] = toupper(some_data.some_text[i]);             if (msgsnd(out_msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {                 fprintf(stderr, "msgsnd failed with error: %s\n", strerror(errno));                 exit(EXIT_FAILURE);             }         }         exit(EXIT_SUCCESS);     default: /* Were the parent...so just exit*/         exit(0);     }  } 

Example Interix Service

In the previous code listing, Example Interix Daemon Code, the msgd daemon was ported to Interix. For this daemon to start at system startup, the daemon must be converted into a service. The changes described and listed in this section are required to convert and install the daemon as a service.

Some of the normal UNIX rules for coding daemons cause problems with the service interface, especially forking, having the parent exit, and then calling setsid() to create a new session. Recall that if the parent process has called exit() , then psxrun.exe treats the program as having exited, and the Windows Service Control Manager reports that the service never started successfully. This is what the existing ported msgd code does.

To fix this problem, modify the code as follows. Notice that calls to fork() , setsid() , and the associated logic have been removed from the wmsgd.c code.

 $ cat wmsgd.c #include <signal.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_TEXT 512     int in_msgid, out_msgid; /*  This function reacts to the signal which is passed in the parameter sig.     This function is called when a signal occurs.     This signal is "normally" received during a system shutdown,     and this is where cleanup is performed.     In this case the Input and Output message queues are deleted. */  void terminate(int sig) { /*  Close the input message queue */      if (msgctl(in_msgid, IPC_RMID, 0) == -1)     fprintf(stderr, "msgctl failed (input queue) error: %s\n", strerror(errno)); /*  Close the output message queue */     if (msgctl(out_msgid, IPC_RMID, 0) == -1)     fprintf(stderr, "msgctl failed (output queue) error: %s\n", strerror(errno));     exit(0); } struct my_msg_st {     long int my_msg_type;     char some_text[BUFSIZ]; }; /*  The main daemon function must intercept the SIGTERM signal generated     for example when the system shuts down.     Otherwise, it sits in an infinite loop, waiting for messages to process     on its input queue */ int main() {     int i;     int running = 1;     struct my_msg_st some_data;     long int msg_to_receive = 0;     struct msqid_ds buf;     (void) signal(SIGTERM, terminate); /* First, set up the input message queue. */     in_msgid = msgget((key_t)1234, 0666  IPC_CREAT  IPC_EXCL);     if (in_msgid == -1) {     fprintf(stderr, "msgget failed err: %s for input queue\n", strerror(errno));     exit(EXIT_FAILURE);     }     if (msgctl(in_msgid, IPC_STAT, &buf) != -1)     printf("Input Queue Permissions are: %o\n", buf.msg_perm.mode); /* Second, set up the output message queue. */     out_msgid = msgget((key_t)1235, 0666  IPC_CREAT  IPC_EXCL);     if (out_msgid == -1) {     fprintf(stderr, "msgget failed err: %s for output queue\n", strerror(errno));     exit(EXIT_FAILURE);     }     if (msgctl(out_msgid, IPC_STAT, &buf) != -1)     printf("Output Queue Permissions are: %o\n", buf.msg_perm.mode); /* Then the messages are retrieved from the input queue, converted, and sent    to the output queue, until an end message is encountered.  */     while(running) {     if (msgrcv(in_msgid, (void *)&some_data, BUFSIZ, msg_to_receive, 0) == -1) {         if (errno != EINTR) {         fprintf(stderr, "msgrcv failed with error: %s\n", strerror(errno));         exit(EXIT_FAILURE);         }         else         continue;     }     i=0;     while(some_data.some_text[i]) some_data.some_text[i++] = toupper (some_data.some_text[i]);     if (msgsnd(out_msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {         fprintf(stderr, "msgsnd failed with error: %s\n", strerror(errno));         exit(EXIT_FAILURE);     }     }     exit(EXIT_SUCCESS); } 

Notice that calls to fork() , setsid() , and the associated logic have been removed from the wmsgd.c code.

To compile and execute the preceding code

  1. To recompile and relink the Windows (daemon) service, use the gcc command:

      $ gcc o wmsgd wmsgd.c   $ ./wmsgd  & 
  2. To launch the test application msg2 to interact with the Windows service, enter the following command:

      $ ./msg2  

    Note that the output displayed is the same as in Example Interix Daemon Code.

  3. To terminate the Windows (daemon) service process, use the following command:

    kill PIDofWmsgd

    (The PID of Wmsgd is found under the PID heading in a ps listing.)

Interix daemons can be installed and executed in two different ways. They mustbe installed and executed as Windows services if they have to run logged on witha Windows account, such as to access network resources. Otherwise, they can berun as conventional daemons by using the same mechanism as conventional UNIX systems, that is, by creating shell scripts in the /etc/rc2.d/ directory that directly start and stop the daemons. Then the init utility can start the daemon when the Interix subsystem initializes.

Because the wmsgd daemon does not need to run logged on to a Windows account, it can be installed by creating a shell script in the /etc/rc2.d directory. The following script can be used for the wmsgd daemon:

 #!/bin/sh # # /etc/init.d/wmsgd # WMSGD=/usr/sbin/wmsgd PATH=/bin:/usr/contrib/bin . /etc/init.d/funcs case  in         start)                 ${WMSGD}                 [ $? = 0 ] && echo "wmsgd started"                 ;;         stop)                 killall ${WMSGD}                 [ $? = 0 ] && echo "wmsgd stopped"                 ;;         *)                 echo "usage: 
 #!/bin/sh # # /etc/init.d/wmsgd # WMSGD=/usr/sbin/wmsgd PATH=/bin:/usr/ contrib /bin . /etc/init.d/funcs case $1 in start) ${WMSGD} [ $? = 0 ] && echo "wmsgd started" ;; stop) killall ${WMSGD} [ $? = 0 ] && echo "wmsgd stopped " ;; *) echo "usage: $0 startstop" ;; esac exit 0 
startstop" ;; esac exit 0

This script should be created and stored in the /etc/init.d directory with a file name of wmsgd , and symbolic links created in /etc/rc2.d as follows:

 K80wmsgd -> ../init.d/wmsgd S80wmsgd -> ../init.d/wmsgd 



UNIX Application Migration Guide
Unix Application Migration Guide (Patterns & Practices)
ISBN: 0735618380
EAN: 2147483647
Year: 2003
Pages: 134

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net