Less crashy in door handler
[tpg/opendispense2.git] / src / server / handler_door.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * handler_doror.c - Door Relay code
6  *
7  * This file is licenced under the 3-clause BSD Licence. See the file
8  * COPYING for full details.
9  */
10 #define DEBUG   1
11 #define USE_POPEN       0
12
13 #include "common.h"
14 #include <stdio.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <signal.h>
20 #if !USE_POPEN
21 # include <unistd.h>
22 #endif
23
24 #define DOOR_UNLOCKED_DELAY     10      // 10 seconds before it re-locks
25
26 // === IMPORTS ===
27
28 // === PROTOTYPES ===
29  int    Door_InitHandler();
30  int    Door_CanDispense(int User, int Item);
31  int    Door_DoDispense(int User, int Item);
32 void    Door_int_SIGCHLDHandler(int signum);
33
34 // === GLOBALS ===
35 tHandler        gDoor_Handler = {
36         "door",
37         Door_InitHandler,
38         Door_CanDispense,
39         Door_DoDispense
40 };
41 char    *gsDoor_Password = "";
42 volatile int    giDoor_ChildTerminated;
43
44 // == CODE ===
45 int Door_InitHandler(void)
46 {       
47         signal(SIGCHLD, Door_int_SIGCHLDHandler);
48         return 0;
49 }
50
51 /**
52  */
53 int Door_CanDispense(int User, int Item)
54 {
55         #if DEBUG
56         printf("Door_CanDispense: (User=%i,Item=%i)\n", User, Item);
57         #endif
58         // Sanity please
59         if( Item != 0 ) return -1;
60         
61         if( !(Bank_GetFlags(User) & USER_FLAG_DOORGROUP) )
62         {
63                 #if DEBUG
64                 printf("Door_CanDispense: User %i not in door\n", User);
65                 #endif
66                 return 1;
67         }
68         
69         #if DEBUG
70         printf("Door_CanDispense: User %i can open the door\n", User);
71         #endif
72         
73         return 0;
74 }
75
76 /**
77  * \brief Actually do a dispense from the coke machine
78  */
79 int Door_DoDispense(int User, int Item)
80 {
81         FILE    *child_stdin;
82         char    buf[512];
83         #if !USE_POPEN
84          int    stdin_pair[2];
85          int    stdout_pair[2];
86         pid_t   childPid;
87         pid_t   parent_pid;
88         #endif
89         
90         #if DEBUG
91         printf("Door_DoDispense: (User=%i,Item=%i)\n", User, Item);
92         #endif
93         
94         // Sanity please
95         if( Item != 0 ) return -1;
96         
97         // Check if user is in door
98         if( !(Bank_GetFlags(User) & USER_FLAG_DOORGROUP) )
99         {
100                 #if DEBUG
101                 printf("Door_CanDispense: User %i not in door\n", User);
102                 #endif
103                 return 1;
104         }
105         
106         #if !USE_POPEN
107         // Create stdin/stdout
108         if( pipe(stdin_pair) || pipe(stdout_pair) )
109         {
110                 perror("pipe");
111                 return -1;
112         }
113         
114         parent_pid = getpid();
115         childPid = fork();
116         
117         if( childPid < 0 )
118         {
119                 perror("fork");
120                 return -1;
121         }
122         
123         // Child process
124         if( childPid == 0 )
125         {
126                 // Close write end of stdin, and set it to #0
127                 close(stdin_pair[1]);   dup2(stdin_pair[0], 0);
128                 // Close read end of stdout, and set it to #1
129                 close(stdout_pair[0]);  dup2(stdout_pair[1], 1);
130                 
131                 execl("llogin", "door", "-w-", NULL);
132                 kill(parent_pid, SIGCHLD);
133                 perror("execl");
134                 exit(-1);
135         }
136         
137         child_stdin = fdopen(stdin_pair[1], "w");
138         close(stdin_pair[0]);   // child stdin read
139         close(stdout_pair[1]);  // child stdout write
140         
141         #else
142         // llogin or other
143         child_stdin = popen("llogin door -w -", "w");
144         if( !child_stdin || child_stdin == (void*)-1 ) {
145                 #if DEBUG
146                 printf("Door_DoDispense: llogin failure\n");
147                 #endif
148                 return -1;
149         }
150         #endif
151         
152         if(fread(buf, 1, 512, child_stdin) == 0)        return -1;
153         
154         // Send password
155         if( fputs(gsDoor_Password, child_stdin) <= 0 )  return -1;
156         fputs("\n", child_stdin);
157         
158         
159         #if DEBUG
160         printf("Door_DoDispense: Door unlock\n");
161         #endif
162         
163         // ATH1 - Unlock door
164         if( fputs("ATH1\n", child_stdin) <= 0)  return -1;
165         
166         // Wait before re-locking
167         sleep(DOOR_UNLOCKED_DELAY);
168
169
170         #if DEBUG
171         printf("Door_DoDispense: Door re-lock\n");
172         #endif
173
174         // Re-lock the door
175         if( fputs("ATH0\n", child_stdin) <= 0 ) return -1;
176         
177         #if !USE_POPEN
178         fclose(child_stdin);
179         close(stdin_pair[1]);   // child stdin write
180         close(stdout_pair[0]);  // child stdout read
181         #else
182         pclose(child_stdin);
183         #endif
184         
185         #if DEBUG
186         printf("Door_DoDispense: User %i opened door\n", User);
187         #endif
188
189         return 0;
190 }
191
192 void Door_int_SIGCHLDHandler(int signum)
193 {
194         signum = 0;     // Snut up
195         giDoor_ChildTerminated = 1;
196 }
197

UCC git Repository :: git.ucc.asn.au