Subject: [clisp-list] with-open-file bug on linux

From: Peter Wood <[email-masked]>
Date: Sat Mar 16 21:55:02 2002

Hi

I've reported this before, but I wasn't sure it was a bug in Clisp or
in Linux.  Now I'm sure it's in Clisp, and it is a serious bug.

I'm using cvs Clisp (but the same thing happened in 2.27) on
Gnu/Linux.

This is what /proc/sys/fs/binfmt_misc/* looks like:

total 84
-rw-r--r--   1 root     root            0 Mar 17 04:53 FAS
-rw-r--r--   1 root     root            0 Mar 17 04:53 LISP
-rw-r--r--   1 root     root            0 Mar 17 04:53 PL
-rw-r--r--   1 root     root            0 Mar 17 04:53 PY
-rw-r--r--   1 root     root            0 Mar 17 04:53 RB
--w-------   1 root     root            0 Mar 17 04:53 register
-rw-r--r--   1 root     root            0 Mar 17 04:53 status

I use the following to register, with the kernel, extensions as
executable by the specified interpreter:

(defun regext (ext interpreter)
  "EXT & INTERPRETER = lower case strings"
  (let ((path (parse-namestring "/proc/sys/fs/binfmt_misc/register")))
    (with-open-file (str path :direction :output)
		    (format str ":~:@(~a~):E::~a::~a:" ext ext interpreter))))

;eg (regext "fas" "/usr/bin/clisp") registers the .fas extension as executable
;   by /usr/bin/clisp with the kernel.
;   you still have to (chmod 7xx xyz.fas)

It works fine.  The problem arises when I try to cancel or disable
extensions using with-open-file *on Clisp*.

This is what happens:

#<output buffered file-stream character #P"bin-write.clisp" @1>
[2]> (with-open-file (str "/proc/sys/fs/binfmt_misc/PY" :direction :output :if-exists :overwrite) (format str "-1"))

*** - UNIX error 22 (EINVAL): Invalid argument
1. Break [3]> (dribble)

Quite apart from the fact that *THIS SHOULD NOT HAPPEN*, the Clisp in
which I issue this call is totally trashed.  Every following call
results in the same Unix error.  In other words, ITS BROKEN.

I can work around it using libc6 #'linux:fopen, but I should NOT have
to do that:

(defun cancel (&optional (name nil))
  "optional NAME = lower case string naming ext to remove"
  (if (null name)
      (let* ((path "/proc/sys/fs/binfmt_misc/status")
	     (fp (linux:fopen path "w")))
	(linux:fputs "-1" fp)
	(linux:fclose fp))
    (let* ((path (format nil "/proc/sys/fs/binfmt_misc/~:@(~a~)" name))
	   (fp (linux:fopen path "w")))
      (linux:fputs "-1" fp)
      (linux:fclose fp))))

;eg (cancel "fas") removes FAS from /proc/sys/fs/binfmt_misc/
;   (cancel) removes all the registered extensions

This is what it should look like, and what it looks like on CMUCL when
I use the same command as the one that trashes Clisp:

Starting /home/prw/cmucl/bin/lisp ...
CMU Common Lisp 18c, running on localhost.localdomain
Send questions and bug reports to your local CMU CL maintainer, 
or to [email-masked]. and [email-masked]. respectively.
Loaded subsystems:
    Python 1.0, target Intel x86
    CLOS based on PCL version:  September 16 92 PCL (f)
* 
* (with-open-file (str "/proc/sys/fs/binfmt_misc/RB"
		     :direction :output
		     :if-exists :overwrite)
		(format str "-1"))
NIL
* (quit)

Correctly removes RB from the enabled extensions.

Regards,
Peter

---

From: Peter Wood <[email-masked]>
Date: Mon Mar 18 14:31:04 2002

Hi

I didn't know Clisp took a :buffered nil keyword for open.  It seems
this is the way to write to peculiar files like some of the ones under
/proc.  It fixes the problem I described in the last post.

Regards,
Peter

---

From: Peter Wood <[email-masked]>
Date: Wed May 15 10:18:02 2002

Hi
> /proc.  It fixes the problem I described in the last post.

But now it's broken again, on:

Linux localhost.localdomain 2.4.18 #1 Sun May 5 00:18:26 CEST 2002
i686 unknown

with:

GNU CLISP 2.28 (released 2002-03-03) (built 3224594596) (memory
3224596933)

Features: 
(clos loop compiler clisp ansi-cl common-lisp lisp=cl interpreter sockets
 generic-streams logical-pathnames screen ffi gettext unicode
 base-char=character pc386 unix)

Using Clisp's 'open' or 'with-open-file' to write to
/proc/sys/fs/binfmt_misc/register results in

unix error 22 EINVAL

while using linux:fopen works fine, as do Bash, Python, Perl and
CMUCL.

The fact that everything else works ok, while Clisp doesn't suggests
once again that there is something wrong with the way Clisp's #'open
works.

Regards,
Peter

BTW binfmt_misc is no longer mounted automatically, but needs a manual
mount (eg an entry in fstab)

---

From: Sam Steingold <[email-masked]>
Date: Wed May 15 11:15:05 2002

> * In message <[email-masked]>
> * On the subject of "Re: [clisp-list] with-open-file bug on linux"
> * Sent on Wed, 15 May 2002 19:18:41 +0200
> * Honorable Peter Wood <[email-masked]> writes:
>
> while using linux:fopen works fine

not for me:

[1]>  (setq s (linux:fopen "/proc/sys/fs/binfmt_misc/register" "w"))
#<FOREIGN-ADDRESS #x081C08C0>
[3]> (linux:fputs "foo" s)
1
[4]> (linux:perror "bar")
bar: Invalid argument

could you please build CLISP --with-debug and figure out why the
write() call in full_write() in unixaux.d:309 fails?

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat7.2 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
The early bird may get the worm, but the second mouse gets the cheese.

---

From: Peter Wood <[email-masked]>
Date: Thu May 16 06:53:05 2002

Hi
> > while using linux:fopen works fine

It will work for you, if you try to write something reasonable.  "foo"
is not reasonable.  The kernel is expecting a string formatted in a
specific way, not "foo".

> #<FOREIGN-ADDRESS #x081C08C0

Try this:

; no error checking
(defun register-extension (ext interpreter)
  "EXT & INTERPRETER = lower case strings"
  (let* ((path "/proc/sys/fs/binfmt_misc/register")
	 (fp (linux:fopen path "w"))
	 (str (format nil ":~:@(~a~):E::~a::~a:" ext ext interpreter)))
    (linux:fputs str fp)
    (linux:fclose fp)))

;eg (register-extension "fas" "/usr/bin/clisp") registers the .fas extension as executable
;   by /usr/bin/clisp with the kernel.
;   you still have to 'chmod +x' your fas files you want to be
executable.

It _does_ work, and 'open' or 'with-open-file' do not.

I will have a look at full_write in unixaux.d

Regards,
Peter

---

From: Peter Wood <[email-masked]>
Date: Thu May 16 08:12:03 2002

Hi,
On Thu, May 16, 2002 at 03:53:03PM +0200, I wrote:

<cut>

> I will have a look at full_write in unixaux.d

Well, maybe I won't ... this is quite strange:

A _combination_ of :buffered nil and setting *print-escape* to nil
appears to work, at least in some cases.  This wasn't necessary
earlier.

;;this works

[56]> (setf register (open "/proc/sys/fs/binfmt_misc/register" :direction :output :buffered nil))
#<output unbuffered file-stream character #P"/proc/sys/fs/binfmt_misc/register"
  @1>
[57]> (setf string (format nil ":~:@(~a~):E::~a::~a:" "fas" "fas" "/usr/bin/clisp"))
":FAS:E::fas::/usr/bin/clisp:"
[58]> (write string :escape nil :stream register)
":FAS:E::fas::/usr/bin/clisp:"
[59]>

;; so does this work  (princ sets *print-escape* and -readably* to nil)

[69]> (princ string register)
":FAS:E::fas::/usr/bin/clisp:"
[70]>

;; so does this!

[77]> (format register "~a" string)
nil

;; these do not

[82]> (format register "~s" string)

*** - UNIX error 22 (EINVAL): Invalid argument
[84]> (prin1 string register)

*** - UNIX error 22 (EINVAL): Invalid argument
1. Break [85]> 
[86]> (write string :stream register)

Regards,
Peter

---

From: Sam Steingold <[email-masked]>
Date: Thu May 16 09:33:02 2002

> * In message <[email-masked]>
> * Sent on Thu, 16 May 2002 17:11:31 +0200

please do, if the problem persists, but first make sure that the data
you are writing is actually what you really want to write!

> appears to work, at least in some cases.  This wasn't necessary

I think the problem is with your settings.
*print-escape* influences "" around strings, and if "write" depends on
the correct format, this may have a decisive effect!

> [77]> (format register "~a" string)

all these write string simply byte by byte.

> [82]> (format register "~s" string)

of course: this writes to register ""..."" (i.e., it sends #\" to the stream)!

> [84]> (prin1 string register)
same.

> *** - UNIX error 22 (EINVAL): Invalid argument

same.

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat7.2 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
Your mouse has moved - WinNT has to be restarted for this to take effect.

---

From: Sam Steingold <[email-masked]>
Date: Thu May 16 13:06:04 2002

> Well, maybe I won't ... this is quite strange:

please do stop in full_write and show me a string which chokes the
write() call there but which goes through cat/echo/cmucl/C &c.

this will be the proof of the pudding.

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat7.2 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
Don't use force -- get a bigger hammer.