examples/udhcp/simple.script: add possibility to use modern "ip"
[oweals/busybox.git] / miscutils / setserial.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * setserial implementation for busybox
4  *
5  *
6  * Copyright (C) 2011 Marek Bečka <yuen@klacno.sk>
7  *
8  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9  */
10 //config:config SETSERIAL
11 //config:       bool "setserial (6.6 kb)"
12 //config:       default y
13 //config:       select PLATFORM_LINUX
14 //config:       help
15 //config:       Retrieve or set Linux serial port.
16
17 //applet:IF_SETSERIAL(APPLET_NOEXEC(setserial, setserial, BB_DIR_BIN, BB_SUID_DROP, setserial))
18
19 //kbuild:lib-$(CONFIG_SETSERIAL) += setserial.o
20
21 #include "libbb.h"
22 #include <assert.h>
23
24 #ifndef PORT_UNKNOWN
25 # define PORT_UNKNOWN            0
26 #endif
27 #ifndef PORT_8250
28 # define PORT_8250               1
29 #endif
30 #ifndef PORT_16450
31 # define PORT_16450              2
32 #endif
33 #ifndef PORT_16550
34 # define PORT_16550              3
35 #endif
36 #ifndef PORT_16550A
37 # define PORT_16550A             4
38 #endif
39 #ifndef PORT_CIRRUS
40 # define PORT_CIRRUS             5
41 #endif
42 #ifndef PORT_16650
43 # define PORT_16650              6
44 #endif
45 #ifndef PORT_16650V2
46 # define PORT_16650V2            7
47 #endif
48 #ifndef PORT_16750
49 # define PORT_16750              8
50 #endif
51 #ifndef PORT_STARTECH
52 # define PORT_STARTECH           9
53 #endif
54 #ifndef PORT_16C950
55 # define PORT_16C950            10
56 #endif
57 #ifndef PORT_16654
58 # define PORT_16654             11
59 #endif
60 #ifndef PORT_16850
61 # define PORT_16850             12
62 #endif
63 #ifndef PORT_RSA
64 # define PORT_RSA               13
65 #endif
66 #ifndef PORT_NS16550A
67 # define PORT_NS16550A          14
68 #endif
69 #ifndef PORT_XSCALE
70 # define PORT_XSCALE            15
71 #endif
72 #ifndef PORT_RM9000
73 # define PORT_RM9000            16
74 #endif
75 #ifndef PORT_OCTEON
76 # define PORT_OCTEON            17
77 #endif
78 #ifndef PORT_AR7
79 # define PORT_AR7               18
80 #endif
81 #ifndef PORT_U6_16550A
82 # define PORT_U6_16550A         19
83 #endif
84
85 #ifndef ASYNCB_HUP_NOTIFY
86 # define ASYNCB_HUP_NOTIFY       0
87 #endif
88 #ifndef ASYNCB_FOURPORT
89 # define ASYNCB_FOURPORT         1
90 #endif
91 #ifndef ASYNCB_SAK
92 # define ASYNCB_SAK              2
93 #endif
94 #ifndef ASYNCB_SPLIT_TERMIOS
95 # define ASYNCB_SPLIT_TERMIOS    3
96 #endif
97 #ifndef ASYNCB_SPD_HI
98 # define ASYNCB_SPD_HI           4
99 #endif
100 #ifndef ASYNCB_SPD_VHI
101 # define ASYNCB_SPD_VHI          5
102 #endif
103 #ifndef ASYNCB_SKIP_TEST
104 # define ASYNCB_SKIP_TEST        6
105 #endif
106 #ifndef ASYNCB_AUTO_IRQ
107 # define ASYNCB_AUTO_IRQ         7
108 #endif
109 #ifndef ASYNCB_SESSION_LOCKOUT
110 # define ASYNCB_SESSION_LOCKOUT  8
111 #endif
112 #ifndef ASYNCB_PGRP_LOCKOUT
113 # define ASYNCB_PGRP_LOCKOUT     9
114 #endif
115 #ifndef ASYNCB_CALLOUT_NOHUP
116 # define ASYNCB_CALLOUT_NOHUP   10
117 #endif
118 #ifndef ASYNCB_SPD_SHI
119 # define ASYNCB_SPD_SHI         12
120 #endif
121 #ifndef ASYNCB_LOW_LATENCY
122 # define ASYNCB_LOW_LATENCY     13
123 #endif
124 #ifndef ASYNCB_BUGGY_UART
125 # define ASYNCB_BUGGY_UART      14
126 #endif
127
128 #ifndef ASYNC_HUP_NOTIFY
129 # define ASYNC_HUP_NOTIFY       (1U << ASYNCB_HUP_NOTIFY)
130 #endif
131 #ifndef ASYNC_FOURPORT
132 # define ASYNC_FOURPORT         (1U << ASYNCB_FOURPORT)
133 #endif
134 #ifndef ASYNC_SAK
135 # define ASYNC_SAK              (1U << ASYNCB_SAK)
136 #endif
137 #ifndef ASYNC_SPLIT_TERMIOS
138 # define ASYNC_SPLIT_TERMIOS    (1U << ASYNCB_SPLIT_TERMIOS)
139 #endif
140 #ifndef ASYNC_SPD_HI
141 # define ASYNC_SPD_HI           (1U << ASYNCB_SPD_HI)
142 #endif
143 #ifndef ASYNC_SPD_VHI
144 # define ASYNC_SPD_VHI          (1U << ASYNCB_SPD_VHI)
145 #endif
146 #ifndef ASYNC_SKIP_TEST
147 # define ASYNC_SKIP_TEST        (1U << ASYNCB_SKIP_TEST)
148 #endif
149 #ifndef ASYNC_AUTO_IRQ
150 # define ASYNC_AUTO_IRQ         (1U << ASYNCB_AUTO_IRQ)
151 #endif
152 #ifndef ASYNC_SESSION_LOCKOUT
153 # define ASYNC_SESSION_LOCKOUT  (1U << ASYNCB_SESSION_LOCKOUT)
154 #endif
155 #ifndef ASYNC_PGRP_LOCKOUT
156 # define ASYNC_PGRP_LOCKOUT     (1U << ASYNCB_PGRP_LOCKOUT)
157 #endif
158 #ifndef ASYNC_CALLOUT_NOHUP
159 # define ASYNC_CALLOUT_NOHUP    (1U << ASYNCB_CALLOUT_NOHUP)
160 #endif
161 #ifndef ASYNC_SPD_SHI
162 # define ASYNC_SPD_SHI          (1U << ASYNCB_SPD_SHI)
163 #endif
164 #ifndef ASYNC_LOW_LATENCY
165 # define ASYNC_LOW_LATENCY      (1U << ASYNCB_LOW_LATENCY)
166 #endif
167 #ifndef ASYNC_BUGGY_UART
168 # define ASYNC_BUGGY_UART       (1U << ASYNCB_BUGGY_UART)
169 #endif
170
171 #ifndef ASYNC_SPD_CUST
172 # define ASYNC_SPD_CUST         (ASYNC_SPD_HI|ASYNC_SPD_VHI)
173 #endif
174 #ifndef ASYNC_SPD_WARP
175 # define ASYNC_SPD_WARP         (ASYNC_SPD_HI|ASYNC_SPD_SHI)
176 #endif
177 #ifndef ASYNC_SPD_MASK
178 # define ASYNC_SPD_MASK         (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI)
179 #endif
180
181 #ifndef ASYNC_CLOSING_WAIT_INF
182 # define ASYNC_CLOSING_WAIT_INF         0
183 #endif
184 #ifndef ASYNC_CLOSING_WAIT_NONE
185 # define ASYNC_CLOSING_WAIT_NONE        65535
186 #endif
187
188 #ifndef _LINUX_SERIAL_H
189 struct serial_struct {
190         int     type;
191         int     line;
192         unsigned int    port;
193         int     irq;
194         int     flags;
195         int     xmit_fifo_size;
196         int     custom_divisor;
197         int     baud_base;
198         unsigned short  close_delay;
199         char    io_type;
200         char    reserved_char[1];
201         int     hub6;
202         unsigned short  closing_wait; /* time to wait before closing */
203         unsigned short  closing_wait2; /* no longer used... */
204         unsigned char   *iomem_base;
205         unsigned short  iomem_reg_shift;
206         unsigned int    port_high;
207         unsigned long   iomap_base;     /* cookie passed into ioremap */
208 };
209 #endif
210
211 //usage:#define setserial_trivial_usage
212 //usage:        "[-abGvz] { DEVICE [PARAMETER [ARG]]... | -g DEVICE... }"
213 //usage:#define setserial_full_usage "\n\n"
214 //usage:        "Print or set serial port parameters"
215 //usage:   "\n"
216 //usage:   "\n""        -a      Print all"
217 //usage:   "\n""        -b      Print summary"
218 //usage:   "\n""        -G      Print as setserial PARAMETERs"
219 //usage:   "\n""        -v      Verbose"
220 //usage:   "\n""        -z      Zero out serial flags before setting"
221 //usage:   "\n""        -g      All args are device names"
222 //usage:   "\n"
223 //usage:   "\n""PARAMETERs: (* = takes ARG, ^ = can be turned off by preceding ^)"
224 //usage:   "\n""        *port, *irq, *divisor, *uart, *baud_base, *close_delay, *closing_wait,"
225 //usage:   "\n""        ^fourport, ^auto_irq, ^skip_test, ^sak, ^session_lockout, ^pgrp_lockout,"
226 //usage:   "\n""        ^callout_nohup, ^split_termios, ^hup_notify, ^low_latency, autoconfig,"
227 //usage:   "\n""        spd_normal, spd_hi, spd_vhi, spd_shi, spd_warp, spd_cust"
228 //usage:   "\n""ARG for uart:"
229 //usage:   "\n""        unknown, 8250, 16450, 16550, 16550A, Cirrus, 16650, 16650V2, 16750,"
230 //usage:   "\n""        16950, 16954, 16654, 16850, RSA, NS16550A, XSCALE, RM9000, OCTEON, AR7,"
231 //usage:   "\n""        U6_16550A"
232
233 // option string is "bGavzgq". "q" is accepted but ignored.
234 #define OPT_PRINT_SUMMARY       (1 << 0)
235 #define OPT_PRINT_FEDBACK       (1 << 1)
236 #define OPT_PRINT_ALL           (1 << 2)
237 #define OPT_VERBOSE             (1 << 3)
238 #define OPT_ZERO                (1 << 4)
239 #define OPT_LIST_OF_DEVS        (1 << 5)
240 /*#define OPT_QUIET             (1 << 6)*/
241
242 #define OPT_MODE_MASK \
243         (OPT_PRINT_ALL | OPT_PRINT_SUMMARY | OPT_PRINT_FEDBACK)
244
245 enum print_mode
246 {
247         PRINT_NORMAL  = 0,
248         PRINT_SUMMARY = (1 << 0),
249         PRINT_FEDBACK = (1 << 1),
250         PRINT_ALL     = (1 << 2),
251 };
252
253 #define CTL_SET                 (1 << 0)
254 #define CTL_CONFIG              (1 << 1)
255 #define CTL_GET                 (1 << 2)
256 #define CTL_CLOSE               (1 << 3)
257 #define CTL_NODIE               (1 << 4)
258
259 static const char serial_types[] ALIGN1 =
260         "unknown\0"             /* 0 */
261         "8250\0"                /* 1 */
262         "16450\0"               /* 2 */
263         "16550\0"               /* 3 */
264         "16550A\0"              /* 4 */
265         "Cirrus\0"              /* 5 */
266         "16650\0"               /* 6 */
267         "16650V2\0"             /* 7 */
268         "16750\0"               /* 8 */
269         "16950\0"               /* 9 UNIMPLEMENTED: also know as "16950/954" */
270         "16954\0"               /* 10 */
271         "16654\0"               /* 11 */
272         "16850\0"               /* 12 */
273         "RSA\0"                 /* 13 */
274 #ifndef SETSERIAL_BASE
275         "NS16550A\0"            /* 14 */
276         "XSCALE\0"              /* 15 */
277         "RM9000\0"              /* 16 */
278         "OCTEON\0"              /* 17 */
279         "AR7\0"                 /* 18 */
280         "U6_16550A\0"           /* 19 */
281 #endif
282 ;
283
284 #ifndef SETSERIAL_BASE
285 # define MAX_SERIAL_TYPE        19
286 #else
287 # define MAX_SERIAL_TYPE        13
288 #endif
289
290 static const char commands[] ALIGN1 =
291         "spd_normal\0"
292         "spd_hi\0"
293         "spd_vhi\0"
294         "spd_shi\0"
295         "spd_warp\0"
296         "spd_cust\0"
297
298         "sak\0"
299         "fourport\0"
300         "hup_notify\0"
301         "skip_test\0"
302         "auto_irq\0"
303         "split_termios\0"
304         "session_lockout\0"
305         "pgrp_lockout\0"
306         "callout_nohup\0"
307         "low_latency\0"
308
309         "port\0"
310         "irq\0"
311         "divisor\0"
312         "uart\0"
313         "baud_base\0"
314         "close_delay\0"
315         "closing_wait\0"
316
317         "autoconfig\0"
318 ;
319
320 enum
321 {
322         CMD_SPD_NORMAL = 0,
323         CMD_SPD_HI,
324         CMD_SPD_VHI,
325         CMD_SPD_SHI,
326         CMD_SPD_WARP,
327         CMD_SPD_CUST,
328
329         CMD_FLAG_SAK,
330         CMD_FLAG_FOURPORT,
331         CMD_FLAG_NUP_NOTIFY,
332         CMD_FLAG_SKIP_TEST,
333         CMD_FLAG_AUTO_IRQ,
334         CMD_FLAG_SPLIT_TERMIOS,
335         CMD_FLAG_SESSION_LOCKOUT,
336         CMD_FLAG_PGRP_LOCKOUT,
337         CMD_FLAG_CALLOUT_NOHUP,
338         CMD_FLAG_LOW_LATENCY,
339
340         CMD_PORT,
341         CMD_IRQ,
342         CMD_DIVISOR,
343         CMD_UART,
344         CMD_BASE,
345         CMD_DELAY,
346         CMD_WAIT,
347
348         CMD_AUTOCONFIG,
349
350         CMD_FLAG_FIRST = CMD_FLAG_SAK,
351         CMD_FLAG_LAST  = CMD_FLAG_LOW_LATENCY,
352 };
353
354 static bool cmd_noprint(int cmd)
355 {
356         return (cmd >= CMD_FLAG_SKIP_TEST && cmd <= CMD_FLAG_CALLOUT_NOHUP);
357 }
358
359 static bool cmd_is_flag(int cmd)
360 {
361         return (cmd >= CMD_FLAG_FIRST && cmd <= CMD_FLAG_LAST);
362 }
363
364 static bool cmd_needs_arg(int cmd)
365 {
366         return (cmd >= CMD_PORT && cmd <= CMD_WAIT);
367 }
368
369 #define ALL_SPD ( \
370         ASYNC_SPD_HI | ASYNC_SPD_VHI | ASYNC_SPD_SHI | \
371         ASYNC_SPD_WARP | ASYNC_SPD_CUST \
372         )
373
374 #define ALL_FLAGS ( \
375         ASYNC_SAK | ASYNC_FOURPORT | ASYNC_HUP_NOTIFY | \
376         ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ | ASYNC_SPLIT_TERMIOS | \
377         ASYNC_SESSION_LOCKOUT | ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP | \
378         ASYNC_LOW_LATENCY \
379         )
380
381 #if (ALL_SPD | ALL_FLAGS) > 0xffff
382 # error "Unexpected flags size"
383 #endif
384
385 static const uint16_t setbits[CMD_FLAG_LAST + 1] =
386 {
387         0,
388         ASYNC_SPD_HI,
389         ASYNC_SPD_VHI,
390         ASYNC_SPD_SHI,
391         ASYNC_SPD_WARP,
392         ASYNC_SPD_CUST,
393
394         ASYNC_SAK,
395         ASYNC_FOURPORT,
396         ASYNC_HUP_NOTIFY,
397         ASYNC_SKIP_TEST,
398         ASYNC_AUTO_IRQ,
399         ASYNC_SPLIT_TERMIOS,
400         ASYNC_SESSION_LOCKOUT,
401         ASYNC_PGRP_LOCKOUT,
402         ASYNC_CALLOUT_NOHUP,
403         ASYNC_LOW_LATENCY
404 };
405
406 #define STR_INFINITE "infinite"
407 #define STR_NONE     "none"
408
409 static const char *uart_type(int type)
410 {
411         if (type > MAX_SERIAL_TYPE)
412                 return "undefined";
413
414         return nth_string(serial_types, type);
415 }
416
417 /* libbb candidate */
418 static int index_in_strings_case_insensitive(const char *strings, const char *key)
419 {
420         int idx = 0;
421
422         while (*strings) {
423                 if (strcasecmp(strings, key) == 0) {
424                         return idx;
425                 }
426                 strings += strlen(strings) + 1; /* skip NUL */
427                 idx++;
428         }
429         return -1;
430 }
431
432 static int uart_id(const char *name)
433 {
434         return index_in_strings_case_insensitive(serial_types, name);
435 }
436
437 static const char *get_spd(int flags, enum print_mode mode)
438 {
439         int idx;
440
441         switch (flags & ASYNC_SPD_MASK) {
442         case ASYNC_SPD_HI:
443                 idx = CMD_SPD_HI;
444                 break;
445         case ASYNC_SPD_VHI:
446                 idx = CMD_SPD_VHI;
447                 break;
448         case ASYNC_SPD_SHI:
449                 idx = CMD_SPD_SHI;
450                 break;
451         case ASYNC_SPD_WARP:
452                 idx = CMD_SPD_WARP;
453                 break;
454         case ASYNC_SPD_CUST:
455                 idx = CMD_SPD_CUST;
456                 break;
457         default:
458                 if (mode < PRINT_FEDBACK)
459                         return NULL;
460                 idx = CMD_SPD_NORMAL;
461         }
462
463         return nth_string(commands, idx);
464 }
465
466 static int get_numeric(const char *arg)
467 {
468         return bb_strtol(arg, NULL, 0);
469 }
470
471 static int get_wait(const char *arg)
472 {
473         if (strcasecmp(arg, STR_NONE) == 0)
474                 return ASYNC_CLOSING_WAIT_NONE;
475
476         if (strcasecmp(arg, STR_INFINITE) == 0)
477                 return ASYNC_CLOSING_WAIT_INF;
478
479         return get_numeric(arg);
480 }
481
482 static int get_uart(const char *arg)
483 {
484         int uart = uart_id(arg);
485
486         if (uart < 0)
487                 bb_error_msg_and_die("illegal UART type: %s", arg);
488
489         return uart;
490 }
491
492 static int serial_open(const char *dev, bool quiet)
493 {
494         int fd;
495
496         fd = device_open(dev, O_RDWR | O_NONBLOCK);
497         if (fd < 0 && !quiet)
498                 bb_simple_perror_msg(dev);
499
500         return fd;
501 }
502
503 static int serial_ctl(int fd, int ops, struct serial_struct *serinfo)
504 {
505         int ret = 0;
506         const char *err;
507
508         if (ops & CTL_SET) {
509                 ret = ioctl(fd, TIOCSSERIAL, serinfo);
510                 if (ret < 0) {
511                         err = "can't set serial info";
512                         goto fail;
513                 }
514         }
515
516         if (ops & CTL_CONFIG) {
517                 ret = ioctl(fd, TIOCSERCONFIG);
518                 if (ret < 0) {
519                         err = "can't autoconfigure port";
520                         goto fail;
521                 }
522         }
523
524         if (ops & CTL_GET) {
525                 ret = ioctl(fd, TIOCGSERIAL, serinfo);
526                 if (ret < 0) {
527                         err = "can't get serial info";
528                         goto fail;
529                 }
530         }
531  nodie:
532         if (ops & CTL_CLOSE)
533                 close(fd);
534
535         return ret;
536  fail:
537         bb_simple_perror_msg(err);
538         if (ops & CTL_NODIE)
539                 goto nodie;
540         exit(EXIT_FAILURE);
541 }
542
543 static void print_flag(const char **prefix, const char *flag)
544 {
545         printf("%s%s", *prefix, flag);
546         *prefix = " ";
547 }
548
549 static void print_serial_flags(int serial_flags, enum print_mode mode,
550                                 const char *prefix, const char *postfix)
551 {
552         int i;
553         const char *spd, *pr;
554
555         pr = prefix;
556
557         spd = get_spd(serial_flags, mode);
558         if (spd)
559                 print_flag(&pr, spd);
560
561         for (i = CMD_FLAG_FIRST; i <= CMD_FLAG_LAST; i++) {
562                 if ((serial_flags & setbits[i])
563                  && (mode > PRINT_SUMMARY || !cmd_noprint(i))
564                 ) {
565                         print_flag(&pr, nth_string(commands, i));
566                 }
567         }
568
569         puts(pr == prefix ? "" : postfix);
570 }
571
572 static void print_closing_wait(unsigned int closing_wait)
573 {
574         switch (closing_wait) {
575         case ASYNC_CLOSING_WAIT_NONE:
576                 puts(STR_NONE);
577                 break;
578         case ASYNC_CLOSING_WAIT_INF:
579                 puts(STR_INFINITE);
580                 break;
581         default:
582                 printf("%u\n", closing_wait);
583         }
584 }
585
586 static void serial_get(const char *device, enum print_mode mode)
587 {
588         int fd, ret;
589         const char *uart, *prefix, *postfix;
590         struct serial_struct serinfo;
591
592         fd = serial_open(device, /*quiet:*/ mode == PRINT_SUMMARY);
593         if (fd < 0)
594                 return;
595
596         ret = serial_ctl(fd, CTL_GET | CTL_CLOSE | CTL_NODIE, &serinfo);
597         if (ret < 0)
598                 return;
599
600         uart = uart_type(serinfo.type);
601         prefix = ", Flags: ";
602         postfix = "";
603
604         switch (mode) {
605         case PRINT_NORMAL:
606                 printf("%s, UART: %s, Port: 0x%.4x, IRQ: %d",
607                         device, uart, serinfo.port, serinfo.irq);
608                 break;
609         case PRINT_SUMMARY:
610                 if (!serinfo.type)
611                         return;
612                 printf("%s at 0x%.4x (irq = %d) is a %s",
613                         device, serinfo.port, serinfo.irq, uart);
614                 prefix = " (";
615                 postfix = ")";
616                 break;
617         case PRINT_FEDBACK:
618                 printf("%s uart %s port 0x%.4x irq %d baud_base %d", device,
619                         uart, serinfo.port, serinfo.irq, serinfo.baud_base);
620                 prefix = " ";
621                 break;
622         case PRINT_ALL:
623                 printf("%s, Line %d, UART: %s, Port: 0x%.4x, IRQ: %d\n",
624                         device, serinfo.line, uart, serinfo.port, serinfo.irq);
625                 printf("\tBaud_base: %d, close_delay: %u, divisor: %d\n",
626                         serinfo.baud_base, serinfo.close_delay,
627                         serinfo.custom_divisor);
628                 printf("\tclosing_wait: ");
629                 print_closing_wait(serinfo.closing_wait);
630                 prefix = "\tFlags: ";
631                 postfix = "\n";
632                 break;
633         default:
634                 assert(0);
635         }
636
637         print_serial_flags(serinfo.flags, mode, prefix, postfix);
638 }
639
640 static int find_cmd(const char *cmd)
641 {
642         int idx;
643
644         idx = index_in_strings_case_insensitive(commands, cmd);
645         if (idx < 0)
646                 bb_error_msg_and_die("invalid flag: %s", cmd);
647
648         return idx;
649 }
650
651 static void serial_set(char **arg, int opts)
652 {
653         struct serial_struct serinfo;
654         int fd;
655
656         fd = serial_open(*arg, /*quiet:*/ false);
657         if (fd < 0)
658                 exit(201);
659
660         serial_ctl(fd, CTL_GET, &serinfo);
661
662         if (opts & OPT_ZERO)
663                 serinfo.flags = 0;
664
665         while (*++arg) {
666                 const char *word;
667                 int invert;
668                 int cmd;
669
670                 word = *arg;
671                 invert = (word[0] == '^');
672                 word += invert;
673
674                 cmd = find_cmd(word);
675
676                 if (cmd_needs_arg(cmd))
677                         if (*++arg == NULL)
678                                 bb_error_msg_and_die(bb_msg_requires_arg, word);
679
680                 if (invert && !cmd_is_flag(cmd))
681                         bb_error_msg_and_die("can't invert %s", word);
682
683                 switch (cmd) {
684                 case CMD_SPD_NORMAL:
685                 case CMD_SPD_HI:
686                 case CMD_SPD_VHI:
687                 case CMD_SPD_SHI:
688                 case CMD_SPD_WARP:
689                 case CMD_SPD_CUST:
690                         serinfo.flags &= ~ASYNC_SPD_MASK;
691                         /* fallthrough */
692                 case CMD_FLAG_SAK:
693                 case CMD_FLAG_FOURPORT:
694                 case CMD_FLAG_NUP_NOTIFY:
695                 case CMD_FLAG_SKIP_TEST:
696                 case CMD_FLAG_AUTO_IRQ:
697                 case CMD_FLAG_SPLIT_TERMIOS:
698                 case CMD_FLAG_SESSION_LOCKOUT:
699                 case CMD_FLAG_PGRP_LOCKOUT:
700                 case CMD_FLAG_CALLOUT_NOHUP:
701                 case CMD_FLAG_LOW_LATENCY:
702                         if (invert)
703                                 serinfo.flags &= ~setbits[cmd];
704                         else
705                                 serinfo.flags |= setbits[cmd];
706                         break;
707                 case CMD_PORT:
708                         serinfo.port = get_numeric(*arg);
709                         break;
710                 case CMD_IRQ:
711                         serinfo.irq = get_numeric(*arg);
712                         break;
713                 case CMD_DIVISOR:
714                         serinfo.custom_divisor = get_numeric(*arg);
715                         break;
716                 case CMD_UART:
717                         serinfo.type = get_uart(*arg);
718                         break;
719                 case CMD_BASE:
720                         serinfo.baud_base = get_numeric(*arg);
721                         break;
722                 case CMD_DELAY:
723                         serinfo.close_delay = get_numeric(*arg);
724                         break;
725                 case CMD_WAIT:
726                         serinfo.closing_wait = get_wait(*arg);
727                         break;
728                 case CMD_AUTOCONFIG:
729                         serial_ctl(fd, CTL_SET | CTL_CONFIG | CTL_GET, &serinfo);
730                         break;
731                 default:
732                         assert(0);
733                 }
734         }
735
736         serial_ctl(fd, CTL_SET | CTL_CLOSE, &serinfo);
737 }
738
739 int setserial_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
740 int setserial_main(int argc UNUSED_PARAM, char **argv)
741 {
742         int opts;
743
744         opts = getopt32(argv, "^" "bGavzgq" "\0" "-1:b-aG:G-ab:a-bG");
745         argv += optind;
746
747         if (!argv[1]) /* one arg only? (nothing to change?) */
748                 opts |= OPT_LIST_OF_DEVS; /* force display */
749
750         if (!(opts & OPT_LIST_OF_DEVS)) {
751                 serial_set(argv, opts);
752                 argv[1] = NULL;
753         }
754
755         /* -v effect: "after setting params, do not be silent, show them" */
756         if (opts & (OPT_VERBOSE | OPT_LIST_OF_DEVS)) {
757                 do {
758                         serial_get(*argv, opts & OPT_MODE_MASK);
759                 } while (*++argv);
760         }
761
762         return EXIT_SUCCESS;
763 }