1/* tportc.c 2 Handle a Taylor UUCP port command. 3 4 Copyright (C) 1992, 1993, 2002 Ian Lance Taylor 5 6 This file is part of the Taylor UUCP uuconf library. 7 8 This library is free software; you can redistribute it and/or 9 modify it under the terms of the GNU Library General Public License 10 as published by the Free Software Foundation; either version 2 of 11 the License, or (at your option) any later version. 12 13 This library is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 Library General Public License for more details. 17 18 You should have received a copy of the GNU Library General Public 19 License along with this library; if not, write to the Free Software 20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 21 22 The author of the program may be contacted at ian@airs.com. 23 */ 24 25#include "uucnfi.h" 26 27#if USE_RCS_ID 28const char _uuconf_tportc_rcsid[] = "$Id: tportc.c,v 1.18 2002/03/05 19:10:43 ian Rel $"; 29#endif 30 31#include <errno.h> 32 33static int ipproto_param P((pointer pglobal, int argc, char **argv, 34 pointer pvar, pointer pinfo)); 35static int ipbaud_range P((pointer pglobal, int argc, char **argv, 36 pointer pvar, pointer pinfo)); 37static int ipdialer P((pointer pglobal, int argc, char **argv, pointer pvar, 38 pointer pinfo)); 39static int ipcunknown P((pointer pglobal, int argc, char **argv, 40 pointer pvar, pointer pinfo)); 41 42/* The string names of the port types. This array corresponds to the 43 uuconf_porttype enumeration. */ 44 45static const char * const azPtype_names[] = 46{ 47 NULL, 48 "stdin", 49 "modem", 50 "direct", 51 "tcp", 52 "tli", 53 "pipe" 54}; 55 56#define CPORT_TYPES (sizeof azPtype_names / sizeof azPtype_names[0]) 57 58/* The command table for generic port commands. The "port" and "type" 59 commands are handled specially. */ 60static const struct cmdtab_offset asPort_cmds[] = 61{ 62 { "protocol", UUCONF_CMDTABTYPE_STRING, 63 offsetof (struct uuconf_port, uuconf_zprotocols), NULL }, 64 { "protocol-parameter", UUCONF_CMDTABTYPE_FN | 0, 65 offsetof (struct uuconf_port, uuconf_qproto_params), ipproto_param }, 66 { "seven-bit", UUCONF_CMDTABTYPE_FN | 2, 67 offsetof (struct uuconf_port, uuconf_ireliable), _uuconf_iseven_bit }, 68 { "reliable", UUCONF_CMDTABTYPE_FN | 2, 69 offsetof (struct uuconf_port, uuconf_ireliable), _uuconf_ireliable }, 70 { "half-duplex", UUCONF_CMDTABTYPE_FN | 2, 71 offsetof (struct uuconf_port, uuconf_ireliable), 72 _uuconf_ihalf_duplex }, 73 { "lockname", UUCONF_CMDTABTYPE_STRING, 74 offsetof (struct uuconf_port, uuconf_zlockname), NULL }, 75 { NULL, 0, 0, NULL } 76}; 77 78#define CPORT_CMDS (sizeof asPort_cmds / sizeof asPort_cmds[0]) 79 80/* The stdin port command table. */ 81static const struct cmdtab_offset asPstdin_cmds[] = 82{ 83 { NULL, 0, 0, NULL } 84}; 85 86#define CSTDIN_CMDS (sizeof asPstdin_cmds / sizeof asPstdin_cmds[0]) 87 88/* The modem port command table. */ 89static const struct cmdtab_offset asPmodem_cmds[] = 90{ 91 { "device", UUCONF_CMDTABTYPE_STRING, 92 offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_zdevice), 93 NULL }, 94 { "baud", UUCONF_CMDTABTYPE_LONG, 95 offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_ibaud), 96 NULL }, 97 { "speed", UUCONF_CMDTABTYPE_LONG, 98 offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_ibaud), 99 NULL }, 100 { "baud-range", UUCONF_CMDTABTYPE_FN | 3, 101 offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipbaud_range }, 102 { "speed-range", UUCONF_CMDTABTYPE_FN | 3, 103 offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipbaud_range }, 104 { "carrier", UUCONF_CMDTABTYPE_BOOLEAN, 105 offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_fcarrier), 106 NULL }, 107 { "hardflow", UUCONF_CMDTABTYPE_BOOLEAN, 108 offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_fhardflow), 109 NULL }, 110 { "dial-device", UUCONF_CMDTABTYPE_STRING, 111 offsetof (struct uuconf_port, 112 uuconf_u.uuconf_smodem.uuconf_zdial_device), 113 NULL }, 114 { "dialer", UUCONF_CMDTABTYPE_FN | 0, 115 offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipdialer }, 116 { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING, 117 offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_pzdialer), 118 NULL }, 119 { NULL, 0, 0, NULL } 120}; 121 122#define CMODEM_CMDS (sizeof asPmodem_cmds / sizeof asPmodem_cmds[0]) 123 124/* The direct port command table. */ 125static const struct cmdtab_offset asPdirect_cmds[] = 126{ 127 { "device", UUCONF_CMDTABTYPE_STRING, 128 offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_zdevice), 129 NULL }, 130 { "baud", UUCONF_CMDTABTYPE_LONG, 131 offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_ibaud), 132 NULL }, 133 { "speed", UUCONF_CMDTABTYPE_LONG, 134 offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_ibaud), 135 NULL }, 136 { "carrier", UUCONF_CMDTABTYPE_BOOLEAN, 137 offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_fcarrier), 138 NULL }, 139 { "hardflow", UUCONF_CMDTABTYPE_BOOLEAN, 140 offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_fhardflow), 141 NULL }, 142 { NULL, 0, 0, NULL } 143}; 144 145#define CDIRECT_CMDS (sizeof asPdirect_cmds / sizeof asPdirect_cmds[0]) 146 147/* The TCP port command table. */ 148static const struct cmdtab_offset asPtcp_cmds[] = 149{ 150 { "service", UUCONF_CMDTABTYPE_STRING, 151 offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_zport), 152 NULL }, 153 { "version", UUCONF_CMDTABTYPE_INT, 154 offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_iversion), 155 NULL }, 156 { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING, 157 offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_pzdialer), 158 NULL }, 159 { NULL, 0, 0, NULL } 160}; 161 162#define CTCP_CMDS (sizeof asPtcp_cmds / sizeof asPtcp_cmds[0]) 163 164/* The TLI port command table. */ 165static const struct cmdtab_offset asPtli_cmds[] = 166{ 167 { "device", UUCONF_CMDTABTYPE_STRING, 168 offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_zdevice), 169 NULL }, 170 { "stream", UUCONF_CMDTABTYPE_BOOLEAN, 171 offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_fstream), 172 NULL }, 173 { "push", UUCONF_CMDTABTYPE_FULLSTRING, 174 offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_pzpush), 175 NULL }, 176 { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING, 177 offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_pzdialer), 178 NULL }, 179 { "server-address", UUCONF_CMDTABTYPE_STRING, 180 offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_zservaddr), 181 NULL }, 182 { NULL, 0, 0, NULL } 183}; 184 185#define CTLI_CMDS (sizeof asPtli_cmds / sizeof asPtli_cmds[0]) 186 187/* The pipe port command table. */ 188static const struct cmdtab_offset asPpipe_cmds[] = 189{ 190 { "command", UUCONF_CMDTABTYPE_FULLSTRING, 191 offsetof (struct uuconf_port, uuconf_u.uuconf_spipe.uuconf_pzcmd), 192 NULL }, 193 { NULL, 0, 0, NULL} 194}; 195 196#define CPIPE_CMDS (sizeof asPpipe_cmds / sizeof asPpipe_cmds[0]) 197 198#undef max 199#define max(i1, i2) ((i1) > (i2) ? (i1) : (i2)) 200#define CCMDS \ 201 max (max (max (CPORT_CMDS, CSTDIN_CMDS), CMODEM_CMDS), \ 202 max (max (CDIRECT_CMDS, CTCP_CMDS), max (CTLI_CMDS, CPIPE_CMDS))) 203 204/* Handle a command passed to a port from a Taylor UUCP configuration 205 file. This can be called when reading either the port file or the 206 sys file. The return value may have UUCONF_CMDTABRET_KEEP set, but 207 not UUCONF_CMDTABRET_EXIT. It assigns values to the elements of 208 qport. The first time this is called, qport->uuconf_zname and 209 qport->uuconf_palloc should be set and qport->uuconf_ttype should 210 be UUCONF_PORTTYPE_UNKNOWN. */ 211 212int 213_uuconf_iport_cmd (qglobal, argc, argv, qport) 214 struct sglobal *qglobal; 215 int argc; 216 char **argv; 217 struct uuconf_port *qport; 218{ 219 boolean fgottype; 220 const struct cmdtab_offset *qcmds; 221 size_t ccmds; 222 struct uuconf_cmdtab as[CCMDS]; 223 size_t i; 224 int iret; 225 226 fgottype = strcasecmp (argv[0], "type") == 0; 227 228 if (fgottype || qport->uuconf_ttype == UUCONF_PORTTYPE_UNKNOWN) 229 { 230 enum uuconf_porttype ttype; 231 232 /* We either just got a "type" command, or this is an 233 uninitialized port. If the first command to a port is not 234 "type", it is assumed to be a modem port. This 235 implementation will actually permit "type" at any point, but 236 will effectively discard any type specific information that 237 appears before the "type" command. This supports defaults, 238 in that the default may be of a specific type while future 239 ports in the same file may be of other types. */ 240 if (! fgottype) 241 ttype = UUCONF_PORTTYPE_MODEM; 242 else 243 { 244 if (argc != 2) 245 return UUCONF_SYNTAX_ERROR; 246 247 for (i = 0; i < CPORT_TYPES; i++) 248 if (azPtype_names[i] != NULL 249 && strcasecmp (argv[1], azPtype_names[i]) == 0) 250 break; 251 252 if (i >= CPORT_TYPES) 253 return UUCONF_SYNTAX_ERROR; 254 255 ttype = (enum uuconf_porttype) i; 256 } 257 258 qport->uuconf_ttype = ttype; 259 260 switch (ttype) 261 { 262 default: 263 case UUCONF_PORTTYPE_STDIN: 264 break; 265 case UUCONF_PORTTYPE_MODEM: 266 qport->uuconf_u.uuconf_smodem.uuconf_zdevice = NULL; 267 qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = NULL; 268 qport->uuconf_u.uuconf_smodem.uuconf_ibaud = 0L; 269 qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L; 270 qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L; 271 qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE; 272 qport->uuconf_u.uuconf_smodem.uuconf_fhardflow = TRUE; 273 qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL; 274 qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL; 275 break; 276 case UUCONF_PORTTYPE_DIRECT: 277 qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL; 278 qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = -1; 279 qport->uuconf_u.uuconf_sdirect.uuconf_fcarrier = FALSE; 280 qport->uuconf_u.uuconf_sdirect.uuconf_fhardflow = TRUE; 281 break; 282 case UUCONF_PORTTYPE_TCP: 283 qport->uuconf_u.uuconf_stcp.uuconf_zport = (char *) "uucp"; 284 qport->uuconf_u.uuconf_stcp.uuconf_iversion = 0; 285 qport->uuconf_u.uuconf_stcp.uuconf_pzdialer = NULL; 286 qport->uuconf_ireliable = (UUCONF_RELIABLE_SPECIFIED 287 | UUCONF_RELIABLE_ENDTOEND 288 | UUCONF_RELIABLE_RELIABLE 289 | UUCONF_RELIABLE_EIGHT 290 | UUCONF_RELIABLE_FULLDUPLEX); 291 break; 292 case UUCONF_PORTTYPE_TLI: 293 qport->uuconf_u.uuconf_stli.uuconf_zdevice = NULL; 294 qport->uuconf_u.uuconf_stli.uuconf_fstream = FALSE; 295 qport->uuconf_u.uuconf_stli.uuconf_pzpush = NULL; 296 qport->uuconf_u.uuconf_stli.uuconf_pzdialer = NULL; 297 qport->uuconf_u.uuconf_stli.uuconf_zservaddr = NULL; 298 qport->uuconf_ireliable = (UUCONF_RELIABLE_SPECIFIED 299 | UUCONF_RELIABLE_ENDTOEND 300 | UUCONF_RELIABLE_RELIABLE 301 | UUCONF_RELIABLE_EIGHT 302 | UUCONF_RELIABLE_FULLDUPLEX); 303 break; 304 case UUCONF_PORTTYPE_PIPE: 305 qport->uuconf_u.uuconf_spipe.uuconf_pzcmd = NULL; 306 break; 307 } 308 309 if (fgottype) 310 return UUCONF_CMDTABRET_CONTINUE; 311 } 312 313 /* See if this command is one of the generic ones. */ 314 qcmds = asPort_cmds; 315 ccmds = CPORT_CMDS; 316 317 for (i = 0; i < CPORT_CMDS - 1; i++) 318 if (strcasecmp (argv[0], asPort_cmds[i].zcmd) == 0) 319 break; 320 321 if (i >= CPORT_CMDS - 1) 322 { 323 /* It's not a generic command, so we must check the type 324 specific commands. */ 325 switch (qport->uuconf_ttype) 326 { 327 case UUCONF_PORTTYPE_STDIN: 328 qcmds = asPstdin_cmds; 329 ccmds = CSTDIN_CMDS; 330 break; 331 case UUCONF_PORTTYPE_MODEM: 332 qcmds = asPmodem_cmds; 333 ccmds = CMODEM_CMDS; 334 break; 335 case UUCONF_PORTTYPE_DIRECT: 336 qcmds = asPdirect_cmds; 337 ccmds = CDIRECT_CMDS; 338 break; 339 case UUCONF_PORTTYPE_TCP: 340 qcmds = asPtcp_cmds; 341 ccmds = CTCP_CMDS; 342 break; 343 case UUCONF_PORTTYPE_TLI: 344 qcmds = asPtli_cmds; 345 ccmds = CTLI_CMDS; 346 break; 347 case UUCONF_PORTTYPE_PIPE: 348 qcmds = asPpipe_cmds; 349 ccmds = CPIPE_CMDS; 350 break; 351 default: 352 return UUCONF_SYNTAX_ERROR; 353 } 354 } 355 356 /* Copy the command table onto the stack and modify it to point to 357 qport. */ 358 _uuconf_ucmdtab_base (qcmds, ccmds, (char *) qport, as); 359 360 iret = uuconf_cmd_args ((pointer) qglobal, argc, argv, as, 361 (pointer) qport, ipcunknown, 0, 362 qport->uuconf_palloc); 363 364 return iret &~ UUCONF_CMDTABRET_EXIT; 365} 366 367/* Handle the "protocol-parameter" command. */ 368 369static int 370ipproto_param (pglobal, argc, argv, pvar, pinfo) 371 pointer pglobal; 372 int argc; 373 char **argv; 374 pointer pvar; 375 pointer pinfo; 376{ 377 struct sglobal *qglobal = (struct sglobal *) pglobal; 378 struct uuconf_proto_param **pqparam = (struct uuconf_proto_param **) pvar; 379 struct uuconf_port *qport = (struct uuconf_port *) pinfo; 380 381 return _uuconf_iadd_proto_param (qglobal, argc - 1, argv + 1, pqparam, 382 qport->uuconf_palloc); 383} 384 385/* Handle the "baud-range" command. */ 386 387/*ARGSUSED*/ 388static int 389ipbaud_range (pglobal, argc, argv, pvar, pinfo) 390 pointer pglobal; 391 int argc ATTRIBUTE_UNUSED; 392 char **argv; 393 pointer pvar; 394 pointer pinfo ATTRIBUTE_UNUSED; 395{ 396 struct sglobal *qglobal = (struct sglobal *) pglobal; 397 struct uuconf_modem_port *qmodem = (struct uuconf_modem_port *) pvar; 398 int iret; 399 400 iret = _uuconf_iint (qglobal, argv[1], 401 (pointer) &qmodem->uuconf_ilowbaud, FALSE); 402 if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS) 403 return iret; 404 405 iret |= _uuconf_iint (qglobal, argv[2], 406 (pointer) &qmodem->uuconf_ihighbaud, FALSE); 407 408 return iret; 409} 410 411/* Handle the "dialer" command. If there is one argument, this names 412 a dialer. Otherwise, the remaining arguments form a command 413 describing the dialer. */ 414 415static int 416ipdialer (pglobal, argc, argv, pvar, pinfo) 417 pointer pglobal; 418 int argc; 419 char **argv; 420 pointer pvar; 421 pointer pinfo; 422{ 423 struct sglobal *qglobal = (struct sglobal *) pglobal; 424 struct uuconf_modem_port *qmodem = (struct uuconf_modem_port *) pvar; 425 struct uuconf_port *qport = (struct uuconf_port *) pinfo; 426 int iret; 427 428 if (argc < 2) 429 return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; 430 431 if (argc > 2) 432 { 433 if (qmodem->uuconf_qdialer == NULL) 434 { 435 struct uuconf_dialer *qnew; 436 size_t clen; 437 438 qnew = ((struct uuconf_dialer *) 439 uuconf_malloc (qport->uuconf_palloc, 440 sizeof (struct uuconf_dialer))); 441 if (qnew == NULL) 442 { 443 qglobal->ierrno = errno; 444 return (UUCONF_MALLOC_FAILED 445 | UUCONF_ERROR_ERRNO 446 | UUCONF_CMDTABRET_EXIT); 447 } 448 449 _uuconf_uclear_dialer (qnew); 450 451 if (qport->uuconf_zname == NULL) 452 qnew->uuconf_zname = (char *) "default port file dialer"; 453 else 454 { 455 clen = strlen (qport->uuconf_zname); 456 qnew->uuconf_zname = 457 (char *) uuconf_malloc (qport->uuconf_palloc, 458 clen + sizeof " dialer"); 459 if (qnew->uuconf_zname == NULL) 460 { 461 qglobal->ierrno = errno; 462 return (UUCONF_MALLOC_FAILED 463 | UUCONF_ERROR_ERRNO 464 | UUCONF_CMDTABRET_EXIT); 465 } 466 467 memcpy ((pointer) qnew->uuconf_zname, 468 (pointer) qport->uuconf_zname, clen); 469 memcpy ((pointer) (qnew->uuconf_zname + clen), 470 (pointer) " dialer", sizeof " dialer"); 471 } 472 473 qnew->uuconf_palloc = qport->uuconf_palloc; 474 475 qmodem->uuconf_qdialer = qnew; 476 } 477 478 iret = _uuconf_idialer_cmd (qglobal, argc - 1, argv + 1, 479 qmodem->uuconf_qdialer); 480 if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS) 481 iret |= UUCONF_CMDTABRET_EXIT; 482 return iret; 483 } 484 else 485 { 486 qmodem->uuconf_pzdialer = NULL; 487 iret = _uuconf_iadd_string (qglobal, argv[1], TRUE, FALSE, 488 &qmodem->uuconf_pzdialer, 489 qport->uuconf_palloc); 490 if (iret != UUCONF_SUCCESS) 491 iret |= UUCONF_CMDTABRET_EXIT; 492 return iret; 493 } 494} 495 496/* Give an error for an unknown port command. */ 497 498/*ARGSUSED*/ 499static int 500ipcunknown (pglobal, argc, argv, pvar, pinfo) 501 pointer pglobal ATTRIBUTE_UNUSED; 502 int argc ATTRIBUTE_UNUSED; 503 char **argv ATTRIBUTE_UNUSED; 504 pointer pvar ATTRIBUTE_UNUSED; 505 pointer pinfo ATTRIBUTE_UNUSED; 506{ 507 return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; 508} 509