File: mg_m_init.c

package info (click to toggle)
mgetty 1.1.21-3
  • links: PTS
  • area: main
  • in suites: potato
  • size: 4,324 kB
  • ctags: 3,291
  • sloc: ansic: 34,054; perl: 5,430; sh: 3,744; makefile: 1,266; tcl: 756; lisp: 283
file content (468 lines) | stat: -rw-r--r-- 11,885 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
#ident "$Id: mg_m_init.c,v 4.7 1999/03/13 19:21:42 gert Exp $ Copyright (c) Gert Doering"

/* mg_m_init.c - part of mgetty+sendfax
 *
 * Initialize (fax-) modem for use with mgetty
 */

#include <stdio.h>
#include "syslibs.h"
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <errno.h>

#ifndef sunos4
#include <sys/ioctl.h>
#endif

#ifdef linux
# include <linux/serial.h>
#endif

#include "mgetty.h"
#include "tio.h"
#include "policy.h"
#include "fax_lib.h"

#if (defined(M_XENIX) && !defined(M_UNIX)) || defined(NEXTSGTTY)
#define O_NOCTTY 0
#endif

chat_action_t	init_chat_actions[] = { { "ERROR", A_FAIL },
					{ "BUSY", A_FAIL },
					{ "NO CARRIER", A_FAIL },
					{ NULL, A_FAIL } };

static int init_chat_timeout = 20;

/* initialize data section */

int mg_init_data _P4( (fd, chat_seq, need_dsr, force_chat_seq), 
		      int fd, char * chat_seq[], 
		      boolean need_dsr, char * force_chat_seq[] )
{
    action_t what_action;
    
    if ( do_chat( fd, chat_seq, init_chat_actions,
		 &what_action, init_chat_timeout, TRUE ) == SUCCESS )
    {
	return SUCCESS;
    }

    /* maybe the modem init failed, because the modem was switched
     * off.  So, we check now that there is a DSR or a CTS signal
     * coming from the modem - and if not, we sleep until it comes back.
     * WARNING: this can fail on systems not allowing to read out the
     * RS232 status lines, thus it is optional, and off by default!
     */
    if ( need_dsr )
    {
        int rs_lines = tio_get_rs232_lines(fd);

	if ( rs_lines != -1 && 
	      (rs_lines & (TIO_F_DSR|TIO_F_CTS) ) == 0 )
	{
	    lprintf( L_WARN, "No DSR/CTS signals, assuming modem is switched off, waiting..." );
	    while( (tio_get_rs232_lines(fd) & (TIO_F_DSR|TIO_F_CTS) ) == 0)
	    {
		sleep(60);
	    }
	}
    }

    /* if init_chat failed because the modem didn't respond, and we have 
     * a "force_chat" sequence, try this.
     * (force_chat might contain DLE ETX for voice modems, or just plain 
     * simple +++ATH0 for data modems (mis-)configured with AT&D0)
     */
    if ( what_action == A_TIMOUT && force_chat_seq != NULL )
    {
	lprintf( L_WARN, "init chat timed out, trying force-init-chat" );

	if ( do_chat( fd, force_chat_seq, init_chat_actions,
		     &what_action, init_chat_timeout, TRUE ) == SUCCESS ||
	     what_action != A_TIMOUT )
        {
	    lprintf( L_NOISE, "force-init succeeded, retrying init-chat");

	    clean_line(fd, 3);
	    if ( do_chat( fd, chat_seq, init_chat_actions,
			 &what_action, init_chat_timeout, TRUE ) == SUCCESS )
	    {
		return SUCCESS;
	    }
        }
    }

    /* either no force_chat available, or that didn't help either: BARF!
     */
    errno = ( what_action == A_TIMOUT )? EINTR: EINVAL;
    lprintf( L_ERROR, "init chat failed, exiting..." );
    return FAIL;
}


/* initialization stuff for fax */

/* initialize fax section */

int mg_init_fax _P5( (fd, mclass, fax_id, fax_only, fax_max_speed),
		      int fd, char * mclass, char * fax_id, 
		      boolean fax_only, int fax_max_speed )
{
    /* find out whether this beast is a fax modem... */

    modem_type = fax_get_modem_type( fd, mclass );
    
    if ( modem_type == Mt_data )
    {
	lprintf( L_NOISE, "no class 2/2.0 faxmodem, no faxing available" );
	return FAIL;
    }
    
    if ( modem_type == Mt_class2_0 )
    {
	/* set adaptive answering, bit order, receiver on */
	
	if ( mdm_command( fax_only? "AT+FAA=0;+FCR=1":
			            "AT+FAA=1;+FCR=1", fd ) == FAIL )
	{
	    lprintf( L_MESG, "cannot set answer/reception flags" );
	}
	if ( fax_set_bor( fd, 1 ) == FAIL )
	{
	    lprintf( L_MESG, "cannot set bit order, trying +BOR=0" );
	    fax_set_bor( fd, 0 );
	}

	/* report everything except NSF (unless asked for it) */
	mdm_command( (modem_quirks & MQ_SHOW_NSF)? "AT+FNR=1,1,1,1"
						 : "AT+FNR=1,1,1,0", fd );
    }

    if ( modem_type == Mt_class2 )
    {
	/* even if we know that it's a class 2 modem, set it to
	 * +FCLASS=0: there are some weird modems out there that won't
	 * properly auto-detect fax/data when in +FCLASS=2 mode...
	 *
	 * Exception: Dr.Neuhaus modems do adaptive answering *only* if in
	 *            +FCLASS=2 mode -> check flag set by auto-detection
	 */
	if ( !fax_only && ! ( modem_quirks & MQ_NEED2 ) )
	{
	    if ( mdm_command( "AT+FCLASS=0", fd ) == FAIL )
	    {
		lprintf( L_MESG, "weird: cannot set class 0" );
	    }
	}

	/* now, set various flags and modem settings. Failures are logged,
	   but ignored - after all, either the modem works or not, we'll
	   see it when answering the phone ... */
    
	/* set adaptive answering, bit order, receiver on */

	if ( mdm_command( fax_only? "AT+FAA=0;+FCR=1":
			            "AT+FAA=1;+FCR=1", fd ) == FAIL )
	{
	    lprintf( L_MESG, "cannot set answer/reception flags" );
	}
	if ( fax_set_bor( fd, 0 ) == FAIL )
	{
	    lprintf( L_MESG, "cannot set bit order. Huh?" );
	}
    }

    /* common part for class 2 and class 2.0 */

    /* local fax station id */
    fax_set_l_id( fd, fax_id );

    /* capabilities */

    if ( fax_set_fdcc( fd, 1, fax_max_speed, 0 ) == FAIL )
    {
	lprintf( L_MESG, "huh? Cannot set +FDCC parameters" );
    }
    
    return SUCCESS;
}


    
/* initialize fax poll server functions (if possible) */
   
extern char * faxpoll_server_file;		/* in faxrec.c */

void faxpoll_server_init _P2( (fd,f), int fd, char * f )
{
    faxpoll_server_file = NULL;
    if ( access( f, R_OK ) != 0 )
    {
	lprintf( L_ERROR, "cannot access/read '%s'", f );
    }
    else if ( mdm_command( modem_type == Mt_class2_0? "AT+FLP=1":"AT+FLPL=1",
			   fd ) == FAIL)
    {
	lprintf( L_WARN, "faxpoll_server_init: no polling available" );
    }
    else
    {
	faxpoll_server_file = f;
	lprintf( L_NOISE, "faxpoll_server_init: OK, waiting for poll" );
    }
}


/* open device (non-blocking / blocking)
 *
 * open with O_NOCTTY, to avoid preventing dial-out processes from
 * getting the line as controlling tty
 */


int mg_open_device _P2 ( (devname, blocking),
		         char * devname, boolean blocking )
{
    int fd;

    if ( ! blocking )
    {
	fd = open(devname, O_RDWR | O_NDELAY | O_NOCTTY );
	if ( fd < 0 )
	{
	    lprintf( L_FATAL, "mod: cannot open line %s", devname );
	    return ERROR;
	}

	/* unset O_NDELAY (otherwise waiting for characters */
	/* would be "busy waiting", eating up all cpu) */
	
	fcntl( fd, F_SETFL, O_RDWR);
    }
    else		/* blocking open */
    {
      again:
	fd = open( devname, O_RDWR | O_NOCTTY );
	    
	if ( fd < 0)
	{
	    if ( errno == EAGAIN ) goto again;
	    
	    lprintf( L_FATAL, "mod: cannot open line %s", devname );
	    return ERROR;
	}
    }
#ifdef NEXTSGTTY
    /* get rid of controlling tty: on NeXT, there is no O_NOCTTY */
    ioctl( fd, TIOCNOTTY, 0 );
#endif

    /* make new fd == stdin if it isn't already */

    if (fd > 0)
    {
	(void) close(0);
	if (dup(fd) != 0)
	{
	    lprintf( L_FATAL, "mod: cannot make %s stdin", devname );
	    return ERROR;
	}
    }

    /* make stdout and stderr, too */

    (void) close(1);
    (void) close(2);
    
    if (dup(0) != 1)
    {
	lprintf( L_FATAL, "mod: cannot dup to stdout"); return ERROR;
    }
    if (dup(0) != 2)
    {
	lprintf( L_FATAL, "mod: cannot dup to stderr"); return ERROR;
    }

    if ( fd > 2 ) (void) close(fd);

    /* switch off stdio buffering */

    setbuf(stdin, (char *) NULL);
    setbuf(stdout, (char *) NULL);
    setbuf(stderr, (char *) NULL);

    return NOERROR;
}

/* init device: toggle DTR (if requested), set TIO values */

int mg_init_device _P4( (fd, toggle_dtr, toggle_dtr_waittime, portspeed ),
		       int fd,
		       boolean toggle_dtr, int toggle_dtr_waittime,
		       unsigned int portspeed )
{
    TIO tio;
    
    if (toggle_dtr)
    {
	lprintf( L_MESG, "lowering DTR to reset Modem" );
	tio_toggle_dtr( fd, toggle_dtr_waittime );
    }

#ifdef TIOCSSOFTCAR
    /* turn off SunOS soft carrier "feature" */

    { int off = 0;
    if ( ioctl( fd, TIOCSSOFTCAR, &off ) < 0 )
	lprintf( L_ERROR, "cannot turn off soft carrier" );
    }
#endif


    /* initialize port */
	
    if ( tio_get( fd, &tio ) == ERROR )
    {
	lprintf( L_FATAL, "cannot get TIO" );
	return ERROR;
    }
    
    tio_mode_sane( &tio, TRUE );	/* initialize all flags */
    tio_set_speed( &tio, portspeed );	/* set bit rate */
    tio_default_cc( &tio );		/* init c_cc[] array */
    tio_mode_raw( &tio );

#ifdef sun
    /* SunOS does not rx with RTSCTS unless carrier present */
    tio_set_flow_control( STDIN, &tio, (DATA_FLOW) & (FLOW_SOFT) );
#else
    tio_set_flow_control( STDIN, &tio, DATA_FLOW );
#endif
    
    if ( tio_set( STDIN, &tio ) == ERROR )
    {
	lprintf( L_FATAL, "cannot set TIO" );
	return ERROR;
    }

#ifdef linux
    /* if port speed is set to 38400, kernel flag might turn it into
     * 57600 or 115200. Make sure the user knows about it!
     */
    if ( portspeed == 38400 )
    {
	struct serial_struct serinfo;

	if ( ioctl( STDIN, TIOCGSERIAL, &serinfo ) == 0 &&
	     ( serinfo.flags & ASYNC_SPD_MASK ) != 0 )
	{
	    lprintf( L_WARN, "WARNING: obsolete setserial spd_hi/spd_vhi used, 38400 is not real port speed" );
	}
    }
#endif

    return NOERROR;
}

/* open + initialize device
 *
 * if first init fails, try again: on Linux and SunOS, the port isn't
 * able anymore after carrier drop, but after reopening it, it is.
 */
int mg_get_device _P5( (devname, blocking_open,
			toggle_dtr, toggle_dtr_waittime, portspeed ),
		      
		        char * devname, boolean blocking_open,
		        boolean toggle_dtr, int toggle_dtr_waittime,
		        unsigned int portspeed)
{
    boolean first_try = TRUE;
    int rs_lines;

    /* most likely, HUPCL was set and so DTR is low right now. Give
     * modem some time to settle down.
     */
    delay(500);
    
    /* open device, make it stdin/out/err */
try_again:
    if ( mg_open_device( devname, blocking_open ) == ERROR )
    {
	lprintf( L_FATAL, "open device %s failed", devname );
	return ERROR;
    }

    /* catch "standard question #17" (DCD drop -> fd invalid -> I/O error) */
    rs_lines = tio_get_rs232_lines(STDIN);
    if ( rs_lines != -1 )
    {
#ifdef linux
	if ( rs_lines & TIO_F_DCD )
	    lprintf( L_MESG, "WARNING: DCD line still active, check modem settings (AT&Dx)" );
#endif
	if ( ! (rs_lines & TIO_F_DSR) )
	    lprintf( L_WARN, "WARNING: DSR is off - modem turned off or bad cable?" );
    }
    
    /* initialize device (hangup, raw, speed). May fail! */
    if ( mg_init_device( STDIN, toggle_dtr, toggle_dtr_waittime,
			 portspeed ) == ERROR )
    {
	if ( first_try )
	{
	    lprintf( L_WARN, "mg_init_device failed, trying again" );
	    first_try = FALSE; goto try_again;
	}

	lprintf( L_FATAL, "mg_init_device failed, exiting" );
	return ERROR;
    }

    return NOERROR;
}
    
		      
/* get a given tty as controlling tty
 *
 * on many systems, this works with ioctl( TIOCSCTTY ), on some
 * others, you have to reopen the device
 */

int mg_get_ctty _P2( (fd, devname), int fd, char * devname )
{
    /* BSD systems, Linux, *NOT* HP-UX */
#if defined( TIOCSCTTY ) && !defined( _HPUX_SOURCE)
    if ( setsid() == -1 && errno != EPERM )
    {
	lprintf( L_ERROR, "cannot make myself session leader (setsid)" );
    }
    if ( ioctl( fd, TIOCSCTTY, NULL ) != 0 )
    {
	lprintf( L_ERROR, "cannot set controlling tty (ioctl)" );
	if ( getppid() != 1 )
	{
	    lprintf( L_WARN, ">>> this might be caused because you have run mgetty/vgetty" );
	    lprintf( L_WARN, ">>> from the command line.  Don't do that, use /etc/inittab!" );
	}
	return ERROR;
    }
#else
    /* SVR3 and earlier */
    fd = open( devname, O_RDWR | O_NDELAY );

    if ( fd == -1 )
    {
        lprintf( L_ERROR, "cannot set controlling tty (open)" );
	return ERROR;
    }

    fcntl( fd, F_SETFL, O_RDWR);		/* unset O_NDELAY */
    close( fd );
#endif						/* !def TIOCSCTTY */

    return NOERROR;
}