Skip to contentSkip to conversation

Make mkiss link its ptys in a predictable manner

PATCH In review Dan Smith 3 participants 7 messages Sep 25, 2010 – Sep 28, 2010

lore
Share & tools
lore

Dan Smith

author
#0 lore raw

PATCH 1/1 Make mkiss link its ptys in a predictable manner

This patch makes mkiss create symlinks for easier scripting. If the -L flag is specified, it uses the base device path as a template for the link:

  # mkiss -L -x 2 /dev/ttyS0
  Awaiting client connects on:
  /dev/ttyS0.0 /dev/ttyS0.1

This makes it easy to subsequently call, for example, kissattach on /dev/ttyS0.0 to access the first TNC port without having to parse the output of mkiss. Without the -L flag, it behaves as it used it. Upon exit, the links are removed.

Signature · 4 lines
Dan Smith
dsmith#danplanet.com, s/#/@/
www.danplanet.com
KK7DS

Index: kiss/mkiss.c
===================================================================
RCS file: /home/ax25-cvs/ax25-tools/kiss/mkiss.c,v retrieving revision 1.7

mkiss.c +34 -5
diff -u -r1.7 mkiss.c
@@ -82,7 +82,7 @@
 static int invalid_ports	= 0;
 static int return_polls		= 0;
 
-static char *usage_string	= "usage: mkiss [-p interval] [-c] [-f] [-h] [-l] [-s speed] [-v] [-x <num_ptmx_devices>] ttyinterface pty ..\n";
+static char *usage_string	= "usage: mkiss [-p interval] [-c] [-f] [-h] [-l] [-s speed] [-v] [-x <num_ptmx_devices>] [-L] ttyinterface pty ..\n";
 
 static int dump_report		= FALSE;
 
@@ -112,6 +112,7 @@
 	unsigned long	txbytes;	/* TX bytes count		*/
 	char		namepts[PATH_MAX];  /* name of the unix98 pts slaves, which
 				       * the client has to use */
+	char		link[PATH_MAX];	/* The link (if any) to namepts	*/
 };
 
 static struct iface *tty	= NULL;
@@ -363,8 +364,10 @@
 	for (i = 0; i < numptys; i++) {
 		if (pty[i]->fd == -1)
 			continue;
-		if (pty[i]->namepts[0] != '\0')
+		if (pty[i]->namepts[0] != '\0') {
+			unlink(pty[i]->link);
 			continue;
+		}
 		tty_unlock(pty[i]->name);
 		close(pty[i]->fd);
 		free(pty[i]);
@@ -432,8 +435,9 @@
 	int ptmxdevices = 0;
 	char *npts;
 	int wrote_info = 0;
+	int link_pty = 0;
 
-	while ((size = getopt(argc, argv, "cfhlp:s:vx:")) != -1) {
+	while ((size = getopt(argc, argv, "cfhlp:s:vx:L")) != -1) {
 		switch (size) {
 		case 'c':
 			crcflag = G8BPQ_CRC;
@@ -462,6 +466,9 @@
 				return 1;
 			}
 			break;
+		case 'L':
+			link_pty = 1;
+			break;
 		case 'v':
 			printf("mkiss: %s\n", VERSION);
 			return 1;
@@ -585,8 +592,28 @@
 				printf("\nAwaiting client connects on:\n");
 			else
 				printf(" ");
-			printf("%s", pty[i]->namepts);
 			wrote_info = 1;
+
+			if (link_pty) {
+				int ret;
+
+				ret = snprintf(pty[i]->link, PATH_MAX,
+					       "%s.%i", tty->name, i);
+				if (ret == -1) {
+					perror("symlink");
+					return 1;
+				}
+
+				unlink(pty[i]->link);
+				ret = symlink(pty[i]->namepts, pty[i]->link);
+				if (ret) {
+					perror("symlink");
+					return 1;
+				}
+				printf("%s", pty[i]->link);
+			} else
+				printf("%s", pty[i]->namepts);
+
 		}
 	}
 
@@ -720,8 +747,10 @@
 	for (i = 0; i < numptys; i++) {
 		if (pty[i]->fd == -1)
 			continue;
-		if (pty[i]->namepts[0] != '\0')
+		if (pty[i]->namepts[0] != '\0') {
+			unlink(pty[i]->link);
 			continue;
+		}
 		tty_unlock(pty[i]->name);
 		close(pty[i]->fd);
 		free(pty[i]);
#1 lore raw

Hello Dan, hello list,

On 2010-09-24 17:35:44 -0700, Dan Smith <[email protected]> wrote in <[email protected]>:

Quoted 11 lines

This patch makes mkiss create symlinks for easier scripting. If the -L flag is specified, it uses the base device path as a template for the link:

  # mkiss -L -x 2 /dev/ttyS0
  Awaiting client connects on:
  /dev/ttyS0.0 /dev/ttyS0.1

This makes it easy to subsequently call, for example, kissattach on /dev/ttyS0.0 to access the first TNC port without having to parse the output of mkiss. Without the -L flag, it behaves as it used it. Upon exit, the links are removed.

thank you for your clean patch.

Personaly, I don't believe it's good to hardcode every eventuality in C. We're working on unix systems and value our powerful scripting languages.

Imho, your approach has some foibles.
1. mkiss is a kiss multiplexer in userspace. It does not even need to be run under root rights.
By symlinking to /dev/, users of your new feature need mkiss to run as root.
2. mkiss could not only be used on true tty's but also on pseudo pty's. Modern linuxes prefer unix98 ptys.
Unix98-pty's are allocated automaticaly via /dev/ptmx.
Imagine you'd try to use two mkiss instances, both called with /dev/ptmx as argument and -L as option. Here the concept completely fails.
Apart from this, it's not permitted to create files in /dev/pts/. Since linux changes so fast, it might be only a matter of time it could be decided that direct operation to /dev/ may not be permitted anymore.

Your feature could be easily implemented as one-liner in a startup script (s/echo// - it's an example):

# cd /dev; M=/dev/ptyr9; PTYS=$(mkiss $M /dev/ptmx /dev/ptmx |tail -1); n=0; for p in $PTYS; do echo ln -fs $p /dev/ptyr9.$n; n=$(($n+1)); done
ln -fs /dev/pts/21 /dev/ptyr9.0
ln -fs /dev/pts/22 /dev/ptyr9.1
# 

Only the cleanup must be done by hand.
On the other hand, if your system crashes or mkiss is killed hard, your patch does also is not able to unlink the symlinks.

vy 73,
- Thomas dl9sau

author
#2 lore raw

Hi Thomas,

Quoted 3 lines

Personaly, I don't believe it's good to hardcode every eventuality in C. We're working on unix systems and value our powerful scripting languages.

I understand, but in an embedded environment, having to parse output like what mkiss provides seems rather silly to me and we may not have all the same scripting facilities as a normal machine. If spawning mkiss from a C program, having to parse the output (especially multi-line output) is gross.

Would you accept a patch to make mkiss output only the names of the slaves if passed an option, such as --short?

Quoted 4 lines

Imho, your approach has some foibles. 1. mkiss is a kiss multiplexer in userspace. It does not even need to be run under root rights. By symlinking to /dev/, users of your new feature need mkiss to run as root.

Fair enough, although only supporting -L if running as root (or writing the links elsewhere) seems plenty reasonable to me. What about a patch that makes -L take a directory in which to write the links?

Quoted 6 lines

2. mkiss could not only be used on true tty's but also on pseudo pty's. Modern linuxes prefer unix98 ptys. Unix98-pty's are allocated automaticaly via /dev/ptmx. Imagine you'd try to use two mkiss instances, both called with /dev/ptmx as argument and -L as option. Here the concept completely fails. Apart from this, it's not permitted to create files in /dev/pts/.

Does anyone do this? Regardless, many programs have options and usage scenarios that are mutually exclusive.

Quoted 3 lines

Since linux changes so fast, it might be only a matter of time it could be decided that direct operation to /dev/ may not be permitted anymore.

I think that's rather unlikely given the move from devfs to udev, and there are other examples that fit this model (syslogd, lircd, etc). Again, since -L is just an optional behavior, it's not like mkiss would break entirely if such a change were to be made.

Quoted 7 lines

Your feature could be easily implemented as one-liner in a startup script (s/echo// - it's an example):

# cd /dev; M=/dev/ptyr9; PTYS=$(mkiss $M /dev/ptmx /dev/ptmx |tail 
-1); n=0; for p in $PTYS; do echo ln -fs $p /dev/ptyr9.$n; 
n=$(($n+1)); done ln -fs /dev/pts/21 /dev/ptyr9.0 ln -fs /dev/pts/22 
/dev/ptyr9.1 #

Well, note that in the above case, you don't catch an error code if mkiss fails to start. I can screen-scrape with the best of them too, but I really don't think it's a better solution in this case.

Quoted 3 lines

Only the cleanup must be done by hand. On the other hand, if your system crashes or mkiss is killed hard, your patch does also is not able to unlink the symlinks.

Nearly everything runs a tmpfs on /dev and has for some time now. That means the hard crash doesn't leave anything lying around, but the scripted solution above does, when mkiss exits.

Please let me know if you would accept a patch for either of the alternate solutions presented above.

Signature · 4 lines
Dan Smith
dsmith#danplanet.com, s/#/@/
www.danplanet.com
KK7DS
#3 lore raw
Quoted 10 lines · Dan Smith

2. mkiss could not only be used on true tty's but also on pseudo

Quoted 6 lines

pty's. Modern linuxes prefer unix98 ptys. Unix98-pty's are allocated automaticaly via /dev/ptmx. Imagine you'd try to use two mkiss instances, both called with /dev/ptmx as argument and -L as option. Here the concept completely fails. Apart from this, it's not permitted to create files in /dev/pts/.

Does anyone do this? Regardless, many programs have options and usage scenarios that are mutually exclusive.

YES All dual port TNC's require the use of psuedo tty's

author
#4 lore raw
Quoted 1 line

YES All dual port TNC's require the use of psuedo tty's

Right, but that's not what he was saying. His example was multiplexing a pty instead of a tty, the use case for which I'm a little fuzzy on.

The whole point of the patch is to make the regular case of using UNIX98 ptys easier in conjunction with the new -x option; it would never be used on its own.

Signature · 3 lines
Dan Smith
www.danplanet.com
KK7DS
#5 lore raw
In reply to Dan Smith

On 2010-09-26 15:50:46 -0700, Dan Smith <[email protected]> wrote in <[email protected]>:

Quoted 11 lines

Hi Thomas,

Quoted 3 lines

Personaly, I don't believe it's good to hardcode every eventuality in C. We're working on unix systems and value our powerful scripting languages.

I understand, but in an embedded environment, having to parse output like what mkiss provides seems rather silly to me and we may not have all the same scripting facilities as a normal machine. If spawning mkiss from a C program, having to parse the output (especially multi-line output) is gross.

Well. Embedded systems have their own special peculiarities. I.e.:

root@dem-thomas-sein-linksys:/dev# :>foobar
-sh: cannot create foobar: Permission denied
On that system, the -L approach in writing to /dev/ would have failed.
Quoted 2 lines

Would you accept a patch to make mkiss output only the names of the slaves if passed an option, such as --short?

Do you have something like "--slave-symlinkname-prefix /path/filename" in mind?

How handle the situation if the destination file already exist? Warn and exit?

Quoted 7 lines
Quoted 4 lines

Imho, your approach has some foibles. 1. mkiss is a kiss multiplexer in userspace. It does not even need to be run under root rights. By symlinking to /dev/, users of your new feature need mkiss to run as root.

Fair enough, although only supporting -L if running as root (or writing the links elsewhere) seems plenty reasonable to me.

Personaly, I see active symlinking as a permanent security problem. Many unix utilities in the past had problems with it. That's why I prefer to operate with environment variables, which are only visable between the father and the son.
There are reasons for allowing a normal user to do symlinks than only root.

Quoted 2 lines

What about a patch
that makes -L take a directory in which to write the links?

Only specifying directory is not sufficient. See the /dev/ptmx example. It should be full-path-to-filename.

Quoted 9 lines
Quoted 6 lines

2. mkiss could not only be used on true tty's but also on pseudo pty's. Modern linuxes prefer unix98 ptys. Unix98-pty's are allocated automaticaly via /dev/ptmx. Imagine you'd try to use two mkiss instances, both called with /dev/ptmx as argument and -L as option. Here the concept completely fails. Apart from this, it's not permitted to create files in /dev/pts/.

Does anyone do this? Regardless, many programs have options and usage scenarios that are mutually exclusive.

A good concept would not have such a limitation.

Quoted 8 lines
Quoted 3 lines

Since linux changes so fast, it might be only a matter of time it could be decided that direct operation to /dev/ may not be permitted anymore.

I think that's rather unlikely given the move from devfs to udev, and there are other examples that fit this model (syslogd, lircd, etc). Again, since -L is just an optional behavior, it's not like mkiss would break entirely if such a change were to be made.

But in this form it would only solve one specific problem (fewer scripting around the startup process), and it has problems on i.e. many embedded systems where the filesystem is mounted ro.

Quoted 10 lines
Quoted 7 lines

Your feature could be easily implemented as one-liner in a startup script (s/echo// - it's an example):

# cd /dev; M=/dev/ptyr9; PTYS=$(mkiss $M /dev/ptmx /dev/ptmx |tail 
-1); n=0; for p in $PTYS; do echo ln -fs $p /dev/ptyr9.$n; 
n=$(($n+1)); done ln -fs /dev/pts/21 /dev/ptyr9.0 ln -fs /dev/pts/22 
/dev/ptyr9.1 #

Well, note that in the above case, you don't catch an error code if mkiss fails to start.

mkiss writes only to stdout if it successfully initialized the ttys. Because $PTYS then is "", the for loop runs 0 times.

Quoted 10 lines

I can screen-scrape with the best of them too,
but I really don't think it's a better solution in this case.

Quoted 3 lines

Only the cleanup must be done by hand. On the other hand, if your system crashes or mkiss is killed hard, your patch does also is not able to unlink the symlinks.

Nearly everything runs a tmpfs on /dev and has for some time now. That means the hard crash doesn't leave anything lying around, but the scripted solution above does, when mkiss exits.

Care must always be taken (i.E. during startup) if a symlink was left behind. A classic is the abnormal termination (segfault, endless loop, ..) of a program.

Quoted 2 lines

Please let me know if you would accept a patch for either of the alternate solutions presented above.

For you it's important to have a built-in capability, I think it suffices as it is.
I'd like to read other comments on this topic. If we do it, I'd prefer a notation that the commandline argument specifies full-path-and-filename where the prefix-0, -.1, .. files could be found after successfull program startup.

vy 73,
- Thomas dl9sau

author
#6 lore raw
Quoted 2 lines

Do you have something like "--slave-symlinkname-prefix /path/filename" in mind?

Sure, that's fine.

Quoted 2 lines

How handle the situation if the destination file already exist? Warn and exit?

Of course, I would rather we explicitly unlink as I did in my original patch. I'll be happy to respin it with fail on EEXIST, if you prefer.

Thanks!

Signature · 3 lines
Dan Smith
www.danplanet.com
KK7DS