]> mj.ucw.cz Git - misc.git/blob - callback.c
Merge with git+ssh://git.ucw.cz/home/mj/GIT/misc.git
[misc.git] / callback.c
1 /*
2  *              Modem Call Back
3  *
4  *              (c) 1995 Martin Mares
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <termios.h>
13 #include <signal.h>
14 #include <utmp.h>
15 #include <sys/wait.h>
16 #include <sys/file.h>
17
18 #define MODEM_PORT "/dev/cua3"
19
20 int modem_handle;
21 int alarm_got;
22 int termios_backed_up;
23 int modem_active;
24 struct termios old_termios;
25
26 struct termios new_termios = {
27         IGNBRK | IGNPAR,
28         0,
29         0,
30         0,
31         N_TTY,
32         { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
33         };
34
35 void err(char *);
36
37 void
38 set_timeout(int n)
39 {
40         alarm_got = 0;
41         alarm(n);
42 }
43
44 void
45 delay(int n)
46 {
47         set_timeout(n);
48         do pause(); while (!alarm_got);
49 }
50
51 void
52 pulse_dtr(void)
53 {
54 int o = new_termios.c_cflag;
55         fprintf(stderr, "Pulsing DTR\n");
56         new_termios.c_cflag &= ~CBAUD;
57         if (tcsetattr(modem_handle, TCSANOW, &new_termios))
58                 err("Unable to lower DTR");
59         delay(2);
60         new_termios.c_cflag = o;
61         if (tcsetattr(modem_handle, TCSANOW, &new_termios))
62                 err("Unable to raise DTR");
63 }
64
65 void
66 send(char *s)
67 {
68         fprintf(stderr, "Sending %s", s);
69         write(modem_handle, s, strlen(s));
70 }
71
72 int
73 wait_for(char *c, int tim)
74 {
75 char *s = c;
76 char b;
77 int l;
78         fprintf(stderr,"Waiting %d sec for %s\n", tim, c);
79         while (*s)
80                 {
81                 set_timeout(tim);
82                 l = read(modem_handle, &b, 1);
83                 if (!l)
84                         err("EOF");
85                 if (l == -1)
86                         {
87                         if (errno == EINTR)
88                                 return 0;
89                         else
90                                 err("Read error");
91                         }
92                 fprintf(stderr, "Got %c\n", b);
93                 if (b == *s)
94                         s++;
95                 else
96                         s = c;
97                 }
98         alarm(0);
99         return 1;
100 }
101
102 void
103 cmd(char *s)
104 {
105         send(s);
106         if (!wait_for("OK",5))
107                 err("Timeout");
108 }
109
110 void
111 drain(void)
112 {
113 char buf[256];
114         if (!fcntl(modem_handle, F_SETFL, O_NONBLOCK))
115                 {
116                 while (read(modem_handle, buf, 256) > 0) ;
117                 fcntl(modem_handle, F_SETFL, 0);
118                 }
119 }
120
121 void
122 modem_init(char *name)
123 {
124         modem_handle = open(name, O_RDWR);
125         if (modem_handle < 0)
126                 err("Unable to open modem device");
127         if (tcgetattr(modem_handle, &old_termios))
128                 err("Unable to fetch old termios");
129         termios_backed_up = 1;
130         new_termios.c_cflag = (old_termios.c_cflag | CRTSCTS) & ~HUPCL;
131         if (!(new_termios.c_cflag & CBAUD))
132                 new_termios.c_cflag |= B19200;
133         if (tcsetattr(modem_handle, TCSANOW, &new_termios))
134                 err("Unable to set termios");
135         modem_active = 1;
136         pulse_dtr();
137         send("ATZ\r\n");
138         delay(2);
139         drain();
140         cmd("ATE0M1Q0\r\n");
141 }
142
143 void
144 err2(char *text)
145 {
146         perror(text);
147 }
148
149 void
150 cleanup(void)
151 {
152         if (modem_handle < 0)
153                 return;
154         fprintf(stderr, "Cleanup.\n");
155         if (modem_active)
156                 {
157                 modem_active = 0;
158                 pulse_dtr();
159                 send("ATZ\n");
160                 delay(1);
161                 pulse_dtr();
162                 }
163         if (termios_backed_up)
164                 {
165                 termios_backed_up = 0;
166                 if (tcsetattr(modem_handle, TCSANOW, &old_termios))
167                         err2("Termios cannot be restored");
168                 }
169         fprintf(stderr, "Done.\n");
170         close(modem_handle);
171         modem_handle = -1;
172 }
173
174 void
175 sig_err(int n)
176 {
177         fprintf(stderr, "Caught fatal signal %d -- aborting !\n", n);
178         cleanup();
179         exit(1);
180 }
181
182 void
183 sig_alarm(int n)
184 {
185         alarm_got = 1;
186         signal(SIGALRM, sig_alarm);
187 }
188
189 void
190 signal_init(void)
191 {
192 int i;
193         for (i=0; i<32; i++)
194                 signal(i, sig_err);
195         signal(SIGALRM, sig_alarm);
196 }
197
198 void
199 err(char *txt)
200 {
201         err2(txt);
202         cleanup();
203         exit(1);
204 }
205
206 int
207 connect(char *nr)
208 {
209 char buf[256];
210 int i;
211         sprintf(buf, "atd%s\r\n", nr);
212         send(buf);
213         i = wait_for("CONNECT", 60);
214         delay(1);
215         drain();
216         return i;
217 }
218
219 struct termios tios = {
220         ICRNL | IXON | IXOFF,
221         OPOST | ONLCR,
222         0,
223         ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE,
224         N_TTY,
225         { 3, 0x1c, 0x7f, 0x15, 4, 0, 1, 0, 0x11, 0x13, 0x1a, 0, 0x12, 0x0f, 0x17,
226                 0x16, 0 }
227         };
228
229 void
230 okay(void)
231 {
232 int pid, i, wt;
233 struct utmp ut;
234 char *port = MODEM_PORT;
235         pid = fork();
236         if (pid < 0)
237                 err("Cannot fork()");
238         if (!pid)
239                 {
240                 setsid();
241                 for (i=0; i<3; i++)
242                         {
243                         close(i);
244                         open(port, O_RDWR);
245                         }
246                 tios.c_cflag = new_termios.c_cflag | HUPCL;
247                 tcsetattr(0, TCSANOW, &tios);
248                 utmpname(_PATH_UTMP);
249                 memset(&ut, 0, sizeof(ut));
250                 strcpy(ut.ut_user, "LOGIN");
251                 strcpy(ut.ut_line, port+5);
252                 strncpy(ut.ut_id, ut.ut_line + 3, sizeof(ut.ut_id));
253                 time(&ut.ut_time);
254                 ut.ut_type = LOGIN_PROCESS;
255                 ut.ut_pid = getpid();
256                 pututline(&ut);
257                 endutent();
258                 wt = open(_PATH_WTMP, O_APPEND|O_WRONLY);
259                 if (wt >= 0)
260                         {
261                         flock(wt, LOCK_EX);
262                         write(wt, &ut, sizeof(ut));
263                         flock(wt, LOCK_UN);
264                         close(wt);
265                         }
266                 execl("/usr/sbin/callback-login", "/usr/sbin/callback-login", NULL);
267                 }
268         else
269                 {
270                 wait(&i);
271                 i = open(MODEM_PORT, O_RDWR);
272                 close(modem_handle);
273                 modem_handle = i;
274                 if (modem_handle >= 0)
275                         tcsetattr(modem_handle, TCSANOW, &new_termios);
276                 }
277 }
278
279 void
280 main(int argc, char **argv)
281 {
282 char *dest;
283 int i;
284         if (geteuid())
285                 {
286                 fprintf(stderr, "Must be run by root!\n");
287                 exit(1);
288                 }
289         if (getuid() != 1000 && getuid())
290                 {
291                 fprintf(stderr,"Only mj is allowed to call this utility!\n");
292                 exit(1);
293                 }
294         if (argc != 2)
295                 {
296                 fprintf(stderr,"Usage: callback <number>\n");
297                 exit(1);
298                 }
299         dest = argv[1];
300         signal_init();
301         for(i=0;i<3;i++)
302                 {
303                 modem_init(MODEM_PORT);
304                 if (connect(dest))
305                         {
306                         fprintf(stderr, "Connected...\n");
307                         okay();
308                         fprintf(stderr, "Disconnecting...\n");
309                         cleanup();
310                         return;
311                         }
312                 cleanup();
313                 fprintf(stderr, "Retrying...\n");
314                 }
315         fprintf(stderr, "Failed.\n");
316         exit(1);
317 }