1 /*        $NetBSD: cu.c,v 1.25 2024/11/03 10:43:27 rillig Exp $       */
2 
3 /*
4  * Copyright (c) 1983, 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #include <getopt.h>
34 #include <inttypes.h>
35 
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)cu.c        8.1 (Berkeley) 6/6/93";
39 #endif
40 __RCSID("$NetBSD: cu.c,v 1.25 2024/11/03 10:43:27 rillig Exp $");
41 #endif /* not lint */
42 
43 #include "tip.h"
44 
45 __dead static void cuhelp(void);
46 __dead static void cuusage(void);
47 
48 /*
49  * Botch the interface to look like cu's
50  */
51 void
cumain(int argc,char * argv[])52 cumain(int argc, char *argv[])
53 {
54           int c, i, phonearg = 0, e;
55           int parity = 0;               /* 0 is no parity */
56           int flow = -1;                /* -1 is "tandem" ^S/^Q */
57           static int helpme = 0, nostop = 0;
58           int useresc = '~';
59           static char sbuf[12];
60           int cmdlineBR;
61 
62           static struct option longopts[] = {
63                     { "help", no_argument,                  &helpme,  1 },
64                     { "escape",         required_argument,  NULL,               'E' },
65                     { "flow", required_argument,  NULL,               'F' },
66                     { "parity",         required_argument,  NULL,               'P' },
67                     { "phone",          required_argument,  NULL,               'c' },
68                     { "port", required_argument,  NULL,               'a' },
69                     { "line", required_argument,  NULL,               'l' },
70                     { "speed",          required_argument,  NULL,               's' },
71                     { "halfduplex",     no_argument,                  NULL,               'h' },
72                     { "nostop",         no_argument,                  &nostop,  1  },
73                     { NULL,             0,                            NULL,               0 }
74           };
75 
76 
77           if (argc < 2)
78                     cuusage();
79 
80           CU = NULL;
81           DV = NULL;
82           BR = DEFBR;
83           cmdlineBR = 0;
84 
85           while((c = getopt_long(argc, argv,
86               "E:F:P:a:p:c:l:ns:hefot0123456789", longopts, NULL)) != -1) {
87 
88                     if (helpme == 1) cuhelp();
89 
90                     switch(c) {
91 
92                     case 'E':
93                               if(strlen(optarg) > 1)
94                                         errx(3, "only one escape character allowed");
95                               useresc = optarg[0];
96                               break;
97                     case 'F':
98                               if (strncmp(optarg, "hard", sizeof("hard") - 1 ) == 0)
99                                         flow = 1;
100                               else
101                                         if (strncmp(optarg, "soft",
102                                             sizeof("soft") - 1 ) == 0)
103                                                   flow = -1;
104                                         else
105                                                   if(strcmp(optarg, "none") != 0)
106                                                             errx(3, "bad flow setting");
107                                                   else
108                                                             flow = 0;
109                               break;
110                     case 'P':
111                               if(strcmp(optarg, "even") == 0)
112                                         parity = -1;
113                               else
114                                         if(strcmp(optarg, "odd") == 0)
115                                                   parity = 1;
116                                         else
117                                                   if(strcmp(optarg, "none") != 0)
118                                                             errx(3, "bad parity setting");
119                                                   else
120                                                             parity = 0;
121                               break;
122                     case 'a':
123                     case 'p':
124                               CU = optarg;
125                               break;
126                     case 'c':
127                               phonearg = 1;
128                               PN = optarg;
129                               break;
130                     case 'l':
131                               if (DV != NULL)
132                                         errx(3,"more than one line specified");
133                               if(strchr(optarg, '/'))
134                                         DV = optarg;
135                               else
136                                         (void)asprintf(&DV, "/dev/%s", optarg);
137                               break;
138                     case 'n':
139                               useresc = -1;
140                               break;
141                     case 's':
142                               BR = (long)strtoi(optarg, NULL, 0, 1, LONG_MAX, &e);
143                               if (e)
144                                         warnc(e, "Conversion of `%s' to a baud rate "
145                                             "failed, using %ld", optarg, BR);
146                               break;
147                     case 'h':
148                               HD = TRUE;
149                               break;
150                     case 'e':
151                               if (parity != 0)
152                                         errx(3, "more than one parity specified");
153                               parity = -1; /* even */
154                               break;
155                               /* Compatibility with Taylor cu */
156                     case 'f':
157                               flow = 0;
158                               break;
159                     case 'o':
160                               if (parity != 0)
161                                         errx(3, "more than one parity specified");
162                               parity = 1; /* odd */
163                               break;
164                     case 't':
165                               HW = 1, DU = -1, DC = 1;
166                               break;
167                     case '0': case '1': case '2': case '3': case '4':
168                     case '5': case '6': case '7': case '8': case '9':
169                               cmdlineBR = cmdlineBR * 10 + (c - '0');
170                               BR = cmdlineBR;
171                               break;
172                     default:
173                               if (nostop == 0)
174                                         cuusage();
175                               break;
176                     }
177           }
178 
179           argc -= optind;
180           argv += optind;
181 
182           switch (argc) {
183           case 1:
184                     if (phonearg)
185                               errx(3, "more than one phone number specified");
186                     else
187                               /* Compatibility with Taylor cu */
188                               if(!strcmp(argv[0], "dir")) {
189                                         HW = 1; DU = -1; DC = 1;
190                               } else
191                                         PN = argv[0];
192                     break;
193           case 0:
194                     /*
195                      * No system or number to call.  We're "direct", so use
196                      * the tty as local.
197                      */
198                     HW = 1; DU = -1; DC = 1;
199                     break;
200           default:
201                     cuusage();
202                     break;
203           }
204 
205           (void)signal(SIGINT, cleanup);
206           (void)signal(SIGQUIT, cleanup);
207           (void)signal(SIGHUP, cleanup);
208           (void)signal(SIGTERM, cleanup);
209           /* (void)signal(SIGCHLD, SIG_DFL) */    /* XXX seems wrong */
210 
211           /*
212            * The "cu" host name is used to define the
213            * attributes of the generic dialer.
214            */
215           (void)snprintf(sbuf, sizeof sbuf, "cu%d", (int)BR);
216           if ((i = hunt(sbuf)) == 0) {
217                     errx(3,"all ports busy");
218           }
219           if (i == -1) {
220                     errx(3, "link down");
221           }
222           setbuf(stdout, NULL);
223           vinit();
224           switch (parity) {
225           case -1:
226                     setparity("even");
227                     break;
228           case 1:
229                     setparity("odd");
230                     break;
231           case 0:
232                     setparity("none");
233                     break;
234           default:
235                     setparity("none");
236                     break;
237           }
238 
239           switch (flow) {
240           case -1:
241                     if(nostop) {
242                               setboolean(value(TAND), FALSE);
243                               setboolean(value(HARDWAREFLOW), FALSE);
244                     }
245                     else {
246                               setboolean(value(TAND), TRUE);
247                               setboolean(value(HARDWAREFLOW), FALSE);
248                     }
249                     break;
250           case 1:
251                     setboolean(value(TAND), FALSE);
252                     setboolean(value(HARDWAREFLOW), TRUE);
253                     break;
254           case 0:
255           default:
256                     setboolean(value(TAND), FALSE);
257                     setboolean(value(HARDWAREFLOW), FALSE);
258                     break;
259           }
260           setcharacter(value(ESCAPE), useresc);
261           setboolean(value(VERBOSE), FALSE);
262           if (HD)
263                     setboolean(value(LECHO), TRUE);
264           if (HW) {
265                     if (ttysetup((speed_t)BR) != 0) {
266                               errx(3, "unsupported speed %ld", BR);
267                     }
268           }
269           if (tip_connect()) {
270                     errx(1, "Connect failed");
271           }
272           if (!HW) {
273                     if (ttysetup((speed_t)BR) != 0) {
274                               errx(3, "unsupported speed %ld", BR);
275                     }
276           }
277 }
278 
279 static void
cuusage(void)280 cuusage(void)
281 {
282           (void)fprintf(stderr, "Usage: cu [options] [phone-number|\"dir\"]\n"
283               "Use cu --help for help\n");
284           exit(8);
285 }
286 
287 static void
cuhelp(void)288 cuhelp(void)
289 {
290           (void)fprintf(stderr,
291               "BSD tip/cu\n"
292               "Usage: cu [options] [phone-number|\"dir\"]\n"
293               " -E,--escape char: Use this escape character\n"
294               " -F,--flow {hard,soft,none}: Use RTS/CTS, ^S/^Q, no flow control\n"
295               " -f: Use no flow control\n"
296               " --nostop: Do not use software flow control\n"
297               " -a, -p,--port port: Use this port as ACU/Dialer\n"
298               " -c,--phone number: Call this number\n"
299               " -h,--halfduplex: Echo characters locally (use \"half duplex\")\n"
300               " -e: Use even parity\n"
301               " -o: Use odd parity\n"
302               " -P,--parity {even,odd,none}: use even, odd, no parity\n"
303               " -l,--line line: Use this device (ttyXX)\n"
304               " -n: Disable escape character processing\n"
305               " -s,--speed,--baud speed,-#: Use this speed\n"
306               " -t: Connect via hard-wired connection\n");
307           exit(0);
308 }
309