[DragonFlyBSD - Bug #3252] tcsetattr/tcgetattr set errno incorrectly on non-TTY

jpipkin bugtracker-admin at leaf.dragonflybsd.org
Sun Jun 28 12:48:51 PDT 2026


Issue #3252 has been updated by jpipkin.

Category set to Kernel

I have a possible solution for this, or at least for the test program provided - I did not check the additional 4 routines, but I cannot say whether it is a correct solution as I do not understand all of the code path, and therefore cannot determine what else might be impacted by the change, and at present I seem to lack the kernel debugging skill to determine this.

What I can say:
1. tc[sg]etattr() live in lib/libc/gen/termios.c, and both basically just call ioctl(2).
2. sys_ioctl(), which is of course in sys/kern/sys_generic.c, is just a call to mapped_ioctl() with a null 4th argument ("map"). mapped_ioctl() immediately follows sys_ioctl() in the same source file.
3. The incorrect ENODEV comes from the call to fo_ioctl() on line 724:
<pre><code class="c">
 716         default:                                                                                           
 717                 /*                                                                                         
 718                  *  If there is a override function,                                                       
 719                  *  call it instead of directly routing the call                                           
 720                  */                                                                                        
 721                 if (map != NULL && iomc->wrapfunc != NULL)                                                 
 722                         error = iomc->wrapfunc(fp, com, ocom, data, cred);                                 
 723                 else                                                                                       
 724                         error = fo_ioctl(fp, com, data, cred, msg);
</code></pre>
4. fo_ioctl() is defined in sys/sys/file2.h; the relevant line is 84:
<pre><code class="c">
 84         error = (*fp->f_ops->fo_ioctl)(fp, com, data, cred, msg);
</code></pre>
5. The *fp->f_ops->fo_ioctl apparently points to devfs_fo_ioctl() in sys/vfs/devfs/devfs_vnops.c.
6. The ENODEV here comes from the call to dev_dioctl on line 1569:
<pre><code class="c">
1569         error = dev_dioctl(dev, com, data, fp->f_flag, ucred, msg, fp);
</code></pre>
7. dev_dioctl() is defined in sys/kern/kern_device.c, and the relevant line is 255:
<pre><code class="c">
255         error = dev->si_ops->d_ioctl(&ap);
</code></pre>
8. The particular d_ioctl in question is apparently mmioctl() defined in sys/kern/kern_memio.c.
9. The incorrect ENODEV at this point comes from the default case, line 506:
<pre><code class="c">
495         switch (minor(dev)) {                                                                               
496         case 0:                                                                                             
497                 error = mem_ioctl(dev, ap->a_cmd, ap->a_data,                                               
498                                   ap->a_fflag, ap->a_cred);                                                 
499                 break;                                                                                      
500         case 3:                                                                                             
501         case 4:                                                                                             
502                 error = random_ioctl(dev, ap->a_cmd, ap->a_data,                                            
503                                      ap->a_fflag, ap->a_cred);                                              
504                 break;                                                                                      
505         default:                                                                                            
506                 error = ENODEV;                                                                             
507                 break;                                                                                      
508         }
</code></pre>
10. Changing line 506 to read "error = ENOTTY;" and recompiling the kernel causes the test program to behave correctly.

The problem is that at present I have no idea how this is going from step 7 to step 8; I have no idea why mmioctl is the contents of the dev->si_ops->d_ioctl variable in step 7. In fact, I have no idea how anything ever is getting set to mmioctl resulting in that function being called, and thus have no idea from where else it might be getting called.

That said, I am running with this change in place at present, and I haven't noticed any ill effects. All the programs I normally use run fine, I am able to build world (and obviously the kernel), as well as various dports, without issue.

----------------------------------------
Bug #3252: tcsetattr/tcgetattr set errno incorrectly on non-TTY
http://bugs.dragonflybsd.org/issues/3252#change-14673

* Author: tonyc
* Status: New
* Priority: Normal
* Category: Kernel
* Target version: 6.4
* Start date: 2020-10-26
----------------------------------------
tcsetattr() and tcgetattr() are documented to fail as follows:

     Upon successful completion, the functions tcgetattr() and tcsetattr()
     return a value of 0.  Otherwise, they return -1 and the global variable
     errno is set to indicate the error, as follows:

...

     [ENOTTY]           The file associated with the fd argument to
                        tcgetattr() or tcsetattr() is not a terminal.

which matches POSIX, but they do not set errno correctly:

$ cc -otcerror tcerror.c
$ ./tcerror
OK: tcgetattr on /dev/null failed as expected
FAIL: tcgetattr on /dev/null set errno incorrectly: Operation not supported by device
OK: tcsetattr failed as expected
FAIL: tcsetattr failure set errno incorrectly: Operation not supported by device
$ uname -a
DragonFly  5.8-RELEASE DragonFly v5.8.3-RELEASE #10: Thu Sep 24 19:19:45 EDT 2020     root at www.shiningsilence.com:/usr/obj/home/justin/release/5_8/sys/X86_64_GENERIC  x86_64

This was discovered while diagnosing perl test failures.

---Files--------------------------------
tcerror.c (1.03 KB)


-- 
You have received this notification because you have either subscribed to it, or are involved in it.
To change your notification preferences, please click here: http://bugs.dragonflybsd.org/my/account


More information about the Bugs mailing list