From: Kaelin Colclasure
Subject: Low-level access to fd's in ACL
Date: 
Message-ID: <3A11E5C4.9150AA0D@acm.org>
Greetings,

I have a requirement to work on a file descriptor directly at the
system-call level (e.g. open, ioctl, read, write, close) from Allegro
Common Lisp. Some browsing through the provided system sources turned up
several un-exported functions in the :excl package and ff:ioctl in the
foreign-functions package. However, I don't seem to be able to get the
latter to work as I would expect.

Consider the following listener transcript:
---8<---
USER(33): (excl::filesys-open "/proc/tnf/trace" nil t)
10
USER(34): (excl::filesys-write-bytes 10 "foo" 0 3 *standard-output*)
T
USER(35): (excl::filesys-write-bytes 10 "foobar" 1 5 *standard-output*)
T
USER(36): (ff::ioctl 10 13 1964)
-1
--->8---

These calls are interacting with a Linux kernel module I am developing.
They result in the following syslog output:
---8<---
Nov 14 17:09:02 vanguard kernel: tnf write 3 bytes
Nov 14 17:09:48 vanguard kernel: tnf write 5
bytes                                                   
--->8---

Notably missing is any sign of the ioctl call -- which Lisp reported as
failing when I know perfectly well all this device does with an ioctl is
spit out a printk() and return success. Just to prove that the ioctl
implementation in the device driver is doing what I expect when called
from C:
---8<---
Nov 14 15:56:30 vanguard kernel: tnf ioctl file = 907f0d40
Nov 14 15:56:30 vanguard kernel: tnf ioctl file = 907f0d40
Nov 14 15:56:42 vanguard kernel: tnf write 4
bytes                                                   
--->8---

What am I missing here? It seems as though Lisp is not liking the ioctl
parameters somehow and is faking a bad return from the system call.

I realize that using unexported functions is in questionable taste -- my
motivation for avoiding defining my own ffi's to the system calls is the
(perhaps misguided) belief that Franz's implementation should be
"safer". Okay, that and I'm lazy... ;-)

-- Kaelin

From: Lieven Marchand
Subject: Re: Low-level access to fd's in ACL
Date: 
Message-ID: <m3itppi4t8.fsf@localhost.localdomain>
Kaelin Colclasure <······@acm.org> writes:

> Notably missing is any sign of the ioctl call -- which Lisp reported as
> failing when I know perfectly well all this device does with an ioctl is
> spit out a printk() and return success. Just to prove that the ioctl
> implementation in the device driver is doing what I expect when called
> from C:
> ---8<---
> Nov 14 15:56:30 vanguard kernel: tnf ioctl file = 907f0d40
> Nov 14 15:56:30 vanguard kernel: tnf ioctl file = 907f0d40
> Nov 14 15:56:42 vanguard kernel: tnf write 4
> bytes                                                   
> --->8---
> 
> What am I missing here? It seems as though Lisp is not liking the ioctl
> parameters somehow and is faking a bad return from the system call.
> 
> I realize that using unexported functions is in questionable taste -- my
> motivation for avoiding defining my own ffi's to the system calls is the
> (perhaps misguided) belief that Franz's implementation should be
> "safer". Okay, that and I'm lazy... ;-)

Try to describe the unexported function you're usurping ;-)

FOREIGN-FUNCTIONS::IOCTL is a SYMBOL.
  It is unbound.
  It is INTERNAL in the FOREIGN-FUNCTIONS package.
  Its function binding is #<Closure FOREIGN-FUNCTION [fcntl] @ #x200bdf22>

It's a binding to fcntl, not ioctl. I've had occasion to use ioctl in
lisp in the past and in general since the third argument is often a
struct for more recent ioctl's you have to make a separate lisp
function for each different ioctl you want to call.

By the way, are you sure an ioctl is the right way for your module to
interact with user level? In general, it's a legacy interface and new
API's should use /proc or sysctl or a separate control device.

-- 
Lieven Marchand <···@bewoner.dma.be>
Lambda calculus - Call us a mad club
From: Kaelin Colclasure
Subject: Re: Low-level access to fd's in ACL
Date: 
Message-ID: <3A131B78.816C5DB3@acm.org>
Lieven Marchand wrote:

[...]
> Try to describe the unexported function you're usurping ;-)
> 
> FOREIGN-FUNCTIONS::IOCTL is a SYMBOL.
>   It is unbound.
>   It is INTERNAL in the FOREIGN-FUNCTIONS package.
>   Its function binding is #<Closure FOREIGN-FUNCTION [fcntl] @ #x200bdf22>
> 
> It's a binding to fcntl, not ioctl. I've had occasion to use ioctl in
> lisp in the past and in general since the third argument is often a
> struct for more recent ioctl's you have to make a separate lisp
> function for each different ioctl you want to call.

Ah, very handy tip. :-) I suppose since I'm mucking with unexported
symbols in an implementation-specific package I really have no right to
complain about what a horribly poor name choice Franz made there. :-O

> By the way, are you sure an ioctl is the right way for your module to
> interact with user level? In general, it's a legacy interface and new
> API's should use /proc or sysctl or a separate control device.

The real "user level" interface to the module is through a set of /proc
filesystem entries -- most generally through /proc/tnf/trace. When the
system is finished, the only caller of this grotty, primitive ioctl
interface will be a command (implemented in C) called 'trex' (trace
execution). However, for testing, I need to be able to call it from the
listener.

I hadn't heard about _sysctl -- probably because the man page says it's
Linux-specific. Still nice to know it's there, tho. Thanks on both
counts!

-- Kaelin
From: Erik Naggum
Subject: Re: Low-level access to fd's in ACL
Date: 
Message-ID: <3183309741355373@naggum.net>
* Kaelin Colclasure <······@acm.org>
| Notably missing is any sign of the ioctl call -- which Lisp reported as
| failing when I know perfectly well all this device does with an ioctl is
| spit out a printk() and return success.

  You don't actually reach the ioctl system call.  The ioctl function
  seems to call _fcntl_ or a proxy for it depending on the platform.
  You would have seen this if you traced the process for system or
  shared library calls, by the way.

| I realize that using unexported functions is in questionable taste --
| my motivation for avoiding defining my own ffi's to the system calls
| is the (perhaps misguided) belief that Franz's implementation should
| be "safer".  Okay, that and I'm lazy... ;-)

  Well, it should be as simple as the following, except that the request
  is extremely dependent on the stupid C macro facility for the "named
  constants" and actually unearthing any values out of it is _painful_.

(def-foreign-call (ioctl "ioctl") (filedes request argument)
  :strings-convert nil
  :arg-checking nil)

#:Erik
-- 
  ALGORITHM: a procedure for solving a mathematical problem in a finite
  number of steps that frequently involves repetition of an operation.
  ALGOREISM: a procedure for solving an electoral problem in a finite
  number of steps that frequently involves repetition of an operation.
From: Kaelin Colclasure
Subject: Re: Low-level access to fd's in ACL
Date: 
Message-ID: <3A131D6D.6FF05E33@acm.org>
Erik Naggum wrote:

[...]
>   You would have seen this if you traced the process for system or
>   shared library calls, by the way.

Good point. And you'd think this would have occurred to me given that
I've recently been groveling through all the ptrace code in the Linux
kernel... Apparently my subconscious is trying to block that whole part
of my existance when I'm enjoying life in Lisp. :-)

> | I realize that using unexported functions is in questionable taste --
> | my motivation for avoiding defining my own ffi's to the system calls
> | is the (perhaps misguided) belief that Franz's implementation should
> | be "safer".  Okay, that and I'm lazy... ;-)
> 
>   Well, it should be as simple as the following, except that the request
>   is extremely dependent on the stupid C macro facility for the "named
>   constants" and actually unearthing any values out of it is _painful_.
> 
> (def-foreign-call (ioctl "ioctl") (filedes request argument)
>   :strings-convert nil
>   :arg-checking nil)

Sufficient to my needs -- thanks!

-- Kaelin