linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alexey Morozov <alex-hp@idisys.iae.nsk.su>
To: linux-hotplug@vger.kernel.org
Subject: Several fixes and enhancements for extented naming rules parameters
Date: Fri, 07 Jan 2005 17:07:46 +0000	[thread overview]
Message-ID: <41DEC1E2.3060806@idisys.iae.nsk.su> (raw)

[-- Attachment #1: Type: text/plain, Size: 2903 bytes --]

Hello!

Playing with udev naming rules, I notices that existing '%e' macro can't 
be really used in several cases (important at least for me). This 
'extended' macro is quite useful if e.g. we try to build nice 
"human-friendly" device naming scheme and strictly separate devices 
names and permissions assignment (to rules.d/* and permissions.d/* 
respectively)

First of all, if one tries to give several names to a device (say, 
create additional symlinks for a CD-RW device like /dev/cdrom, 
/dev/cdwriter) udev ends up w/ errors.

Also I really doubt if %e w/ existing rules processing code can be used 
in constructions like /dev/discs/disc%e/disc and other devfs-like naming 
schemes.

So I decided to patch it a bit to achieve such functionality. You can 
find this patch in the attachment.

Also I'd like to have another macro. While %e is substituted w/ nothing for
'mydevice%e' if /dev/mydevice doesn't exist yet, this new macro always 
substituted w/ a non-negative number. I called it %N, but in fact these 
names can be changed in future. This is particularly useful for names 
like /dev/discs/disc%N/{.....} and allows to simplify devfs-like naming 
scripts.

And the last macro I have invented so far ;-) (don't be scared, I'm 
almost satisfied ;-)), is also about unique file names. I'd like to 
create entries like /dev/cdrom (i.e. only for a first CD-ROM in the 
system) w/o extra script work, just because udev anyway has all required 
info in its database. So this macro (which I called %U) just does a 
small subset of what %e does.

I should note, that all these three macros should be used only once per 
name token (currently, constructions like discs/disc%N/part%N are 
prohibited, I doubt this is a real limitation anyway), but the could be 
freely used in constructions like the following: SYMLINK="cdroms/cdrom%N 
cdroms/cdwriter%N cdrom/cdrom%U".

Also I made a patch for (optional) compilation of udev w/ a system-wide 
installed sysfs libraries. I'm not sure it's a good idea 'for everyone' 
but if we anyway have libsysfs and it's fresh enough to seamlessly work 
w/ udev, I don't see any reasons to have a separate copy right in udev 
source tree. Probably I make a mistake, but it worked /for me/ so far, 
and hey, it's optional anyway.

Hopefully, I'm not just another another wheel re-inventer, and if so, 
please tell me that, I'll try to be more cautious next time ;-).

In the attachments you'll find described patches (for the udev-0.50), 
sample rules file and scripts, mentioned in rules files. Patches should 
be applied in next order:

%patch -p1 -b .system_sysfs (optional)
%patch1 -p1 -b .efmt_fixes
%patch2 -p1 -b .Nfmt
%patch3 -p1 -b .Ufmt
%patch4 -p1 -b .compile_warnings (probably, also optional)

These patches probably could peacefully co-exist w/ recent Mandrake's 
patches for udev.

Thank you for your attention.

Sincerely yours,
Alexey Morozov.

[-- Attachment #2: cd-names.conf --]
[-- Type: text/plain, Size: 1692 bytes --]

# -*- mode: shell-script; coding: utf-8 -*-
# Configuration options for cd-names.sh
#
# DRIVETYPE_PRIO (= <string>)
# Allows to change order in which capabilities will be examined (and
# thus reported). This can lead to naming schemes with different
# primary names. Possible capabilities names are: CD, DVD, CDRW and
# DVDRW. CDROMs are always assumed as being capable to handle CD
# (obvious :-))
# If value isn't set "DVDRW CDRW DVD" is used by default.
DRIVETYPE_PRIO="DVDRW CDRW DVD"

# DO_ALL_LINKS (= 0/1)
# Report all possible names for a given device, not only one for most
# priority capability supported by the device. This can lean to e.g.
# DVD-RW drive to get '/dev/cdroms/dvdwriter0' as its name and
# '/dev/cdroms/dvd0', '/dev/cdroms/cdwriter0' and '/dev/cdroms/cdrom0'
# as symlinks to '/dev/cdroms/dvdwriter0'
# Default is to report all names
#DO_ALL_LINKS=0

# DO_ROOT_LINKS (= 0/1)
# Additionally to all entries in '/dev/cdroms/' folder, make symbolic
# links to a given device right from '/dev/'. This allows to have
# links like '/dev/cdrom' -> '/dev/cdroms/cdrom0' etc
# Default is to do root links
#DO_ROOT_LINKS=0

# PRIMARY_SUFFIX (= <udev device pattern>)
# This suffix will be appended to all device names from '/dev/cdroms/'
# folder. See 'man 8 udev' for more info.
# Default value is '%N' (NOTE: '%N' requires additional patch to
# udev as of version 046!)
#PRIMARY_SUFFIX="%e"

# SECONDARY_SUFFIX (= <udev device pattern>)
# This suffix will be appended to all device names from '/dev/' if
# such entries are to be created (see DO_ROOT_LINKS)
# Default value is '%V" (NOTE: '%U' requires additional patch to
# udev as of version 046!)
#SECONDARY_SUFFIX="%e"



[-- Attachment #3: cd-names.sh --]
[-- Type: application/x-shellscript, Size: 5678 bytes --]

[-- Attachment #4: drive-names.sh --]
[-- Type: application/x-shellscript, Size: 3247 bytes --]

[-- Attachment #5: udev-0.46-alt-Nfmt.patch --]
[-- Type: text/x-patch, Size: 3494 bytes --]

diff -urN udev-046.orig/namedev.c udev-046/namedev.c
--- udev-046.orig/namedev.c	2004-12-28 02:44:57 +0600
+++ udev-046/namedev.c	2004-12-28 02:48:45 +0600
@@ -178,19 +178,13 @@
 	return -1;
 }
 
-/** Finds the lowest positive N such that <name>N isn't present in 
- *  $(udevroot) either as a file or a symlink.
- *
- *  @param  name                Name to check for
- *  @return                     0 if <name> didn't exist and N otherwise.
+/** Internal function used by find_free_number and
+ *  find_free_number_zerobase
  */
-static int find_free_number(struct udevice *udev, const char *name, const char *tail)
+static int find_free_number_internal(struct udevice *udev, const char *name, const char* tail, char *filename, int maxsize)
 {
-	char filename[NAME_SIZE];
 	int num = 0;
 	struct udevice db_udev;
-
-	snprintf(filename, NAME_SIZE, "%s%s", name, tail);
 	while (1) {
 		dbg("look for existing node '%s'", filename);
 		memset(&db_udev, 0x00, sizeof(struct udevice));
@@ -204,11 +198,36 @@
 			info("find_free_number gone crazy (num=%d), aborted", num);
 			return -1;
 		}
-		snprintf(filename, NAME_SIZE, "%s%d%s", name, num, tail);
-		filename[NAME_SIZE-1] = '\0';
+		snprintf(filename, maxsize, "%s%d%s", name, num, tail);
 	}
 }
 
+/** Finds the lowest positive N such that <name>N isn't present in 
+ *  $(udevroot) either as a file or a symlink.
+ *
+ *  @param  name                Name to check for
+ *  @return                     0 if <name> didn't exist and N otherwise.
+ */
+static int find_free_number(struct udevice *udev, const char *name, const char *tail)
+{
+	char filename[NAME_SIZE];
+	snprintf(filename, NAME_SIZE, "%s%s", name, tail);
+	return find_free_number_internal(udev, name, tail, filename, NAME_SIZE);
+}
+
+/** Finds the lowest non-negative N such that <name>N isn't present in 
+ *  $(udevroot) either as a file or a symlink.
+ *
+ *  @param  name                Name to check for
+ *  @return                     0 if <name> didn't exist and N otherwise.
+ */
+static int find_free_number_zerobase(struct udevice *udev, const char *name, const char *tail)
+{
+	char filename[NAME_SIZE];
+	snprintf(filename, NAME_SIZE, "%s%d%s", name, 0, tail);
+	return find_free_number_internal(udev, name, tail, filename, NAME_SIZE);
+}
+
 static void apply_format(struct udevice *udev, char *string, size_t maxsize,
 			 struct sysfs_class_device *class_dev,
 			 struct sysfs_device *sysfs_device);
@@ -344,6 +363,18 @@
 			}
 			strfieldcatmax(string, tail, maxsize);
 			return;
+		case 'N':
+			if (!use_ext) {
+				dbg("prohibited usage of attribute %%e");
+				break;
+			}
+			/* prohibite "extended" attributes in tail */
+			apply_format_token(udev, tail, NAME_SIZE, class_dev, sysfs_device, 0);
+			next_free_number = find_free_number_zerobase(udev, string, tail);
+			sprintf(temp2, "%d", next_free_number);
+			strfieldcatmax(string, temp2, maxsize);
+			strfieldcatmax(string, tail, maxsize);
+			return;
 		default:
 			dbg("unknown substitution type '%%%c'", c);
 			break;
diff -urN udev-046.orig/udev.8.in udev-046/udev.8.in
--- udev-046.orig/udev.8.in	2004-11-19 01:39:15 +0600
+++ udev-046/udev.8.in	2004-12-28 02:49:59 +0600
@@ -285,6 +285,10 @@
 can be used to create compatibility symlinks and enumerate devices of
 the same type originating from different kernel subsystems.
 .TP
+.B %N
+Similar to %e but always substituted by a smallest non-negative number
+giving an unique device node.
+.TP
 .B %%
 The '%' character itself.
 .P

[-- Attachment #6: udev-0.46-alt-Ufmt.patch --]
[-- Type: text/x-patch, Size: 1318 bytes --]

diff -urN udev-046.orig/namedev.c udev-046/namedev.c
--- udev-046.orig/namedev.c	2004-12-28 02:50:52 +0600
+++ udev-046/namedev.c	2004-12-28 02:51:21 +0600
@@ -375,6 +375,22 @@
 			strfieldcatmax(string, temp2, maxsize);
 			strfieldcatmax(string, tail, maxsize);
 			return;
+		case 'U':
+			if (!use_ext) {
+				dbg("prohibited usage of attribute %%e");
+				break;
+			}
+			/* prohibite "extended" attributes in tail */
+			apply_format_token(udev, tail, NAME_SIZE, class_dev, sysfs_device, 0);
+			{
+				struct udevice db_udev;
+				strfieldcatmax(string, tail, maxsize);
+				if (0 == udev_db_get_device_byname(&db_udev, string)) {
+					/* device exists */
+					string[0] = '\0';
+				}
+			}
+			return;
 		default:
 			dbg("unknown substitution type '%%%c'", c);
 			break;
diff -urN udev-046.orig/udev.8.in udev-046/udev.8.in
--- udev-046.orig/udev.8.in	2004-12-28 02:50:52 +0600
+++ udev-046/udev.8.in	2004-12-28 02:52:36 +0600
@@ -289,6 +289,11 @@
 similar to %e but always substituted by a smallest non-negative number
 giving an unique device node.
 .TP
+.B %N
+If a device node already exists with the name, the entire name is skipped.
+This allows to create, say, /dev/cdrom (usually a link) but not /dev/cdrom1
+and only if /dev/cdrom doesn't exist before
+.TP
 .B %%
 The '%' character itself.
 .P

[-- Attachment #7: udev-0.46-alt-compile_warnings.patch --]
[-- Type: text/x-patch, Size: 307 bytes --]

diff -urN udev-046.orig/udev_db.c udev-046/udev_db.c
--- udev-046.orig/udev_db.c	2004-12-09 22:10:53 +0600
+++ udev-046/udev_db.c	2004-12-09 22:12:28 +0600
@@ -30,6 +30,7 @@
 #include <string.h>
 #include <errno.h>
 #include <dirent.h>
+#include <unistd.h>
 
 #include <sysfs/libsysfs.h>
 #include "udev.h"

[-- Attachment #8: udev-0.50-alt-system_sysfs.patch --]
[-- Type: text/x-patch, Size: 26971 bytes --]

diff -urN udev-050.orig/extras/scsi_id/Makefile udev-050/extras/scsi_id/Makefile
--- udev-050.orig/extras/scsi_id/Makefile	2004-12-18 11:53:07 +0600
+++ udev-050/extras/scsi_id/Makefile	2005-01-02 22:15:19 +0600
@@ -31,6 +31,11 @@
 override CFLAGS+=-Wall -fno-builtin
 
 PROG=scsi_id
+
+ifeq ($(strip $(SYS_SYSFS)),)
+CPPFLAGS = -I../../libsysfs
+endif
+
 SYSFS=-lsysfs
 
 #
@@ -53,7 +58,7 @@
 		echo $(INSTALL_DATA) -D ./scsi_id.config  $(DESTDIR)$(etcdir); \
 		$(INSTALL_DATA) -D ./scsi_id.config $(DESTDIR)$(etcdir)/scsi_id.config; \
 	fi
-	
+
 uninstall:
 	-rm $(DESTDIR)$(sbindir)/$(PROG)
 	-rm $(DESTDIR)$(mandir)/man8/scsi_id.8
@@ -73,7 +78,7 @@
 spotless: clean
 
 .c.o:
-	$(QUIET) $(CC) $(CFLAGS) -c -o $@ $<
+	$(QUIET) $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 $(PROG):	$(OBJS)
 	$(QUIET) $(LD) $(LDFLAGS) -o $(PROG) $(CRT0) $(OBJS) $(SYSFS) $(LIB_OBJS) $(ARCH_LIB_OBJS)
diff -urN udev-050.orig/extras/volume_id/Makefile udev-050/extras/volume_id/Makefile
--- udev-050.orig/extras/volume_id/Makefile	2004-12-18 11:53:07 +0600
+++ udev-050/extras/volume_id/Makefile	2005-01-02 22:13:39 +0600
@@ -28,14 +28,24 @@
 INSTALL_DATA  = ${INSTALL} -m 644
 INSTALL_SCRIPT = ${INSTALL_PROGRAM}
 
+ifeq ($(strip $(SYS_SYSFS)),)
+CPPFLAGS = -I../../libsysfs
+endif
+
 override CFLAGS+=-Wall -fno-builtin -Wchar-subscripts \
 		 -Wpointer-arith -Wcast-align -Wsign-compare
 
 override CFLAGS+=-D_FILE_OFFSET_BITS=64
 
-OBJS = volume_id.o udev_volume_id.o dasdlabel.o $(SYSFS)
+OBJS = volume_id.o udev_volume_id.o dasdlabel.o
 HEADERS = volume_id.h dasdlabel.h
 
+ifeq ($(strip $(SYS_SYSFS)),)
+OBJS += $(SYSFS)
+else
+LDFLAGS += $(SYS_SYSFS)
+endif
+
 $(OBJS): $(HEADERS)
 
 .c.o:
diff -urN udev-050.orig/extras/volume_id/udev_volume_id.c udev-050/extras/volume_id/udev_volume_id.c
--- udev-050.orig/extras/volume_id/udev_volume_id.c	2004-12-18 11:53:07 +0600
+++ udev-050/extras/volume_id/udev_volume_id.c	2005-01-02 20:09:11 +0600
@@ -28,7 +28,7 @@
 #include <ctype.h>
 #include <sys/ioctl.h>
 
-#include "../../libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 #include "../../udev_utils.h"
 #include "../../logging.h"
 #include "volume_id.h"
diff -urN udev-050.orig/libsysfs/dlist.c udev-050/libsysfs/dlist.c
--- udev-050.orig/libsysfs/dlist.c	2004-12-18 11:53:07 +0600
+++ udev-050/libsysfs/dlist.c	2005-01-02 20:09:11 +0600
@@ -27,7 +27,7 @@
  * delete function.  Otherwise dlist will just use free.
 
 */
-#include "dlist.h"
+#include "sysfs/dlist.h"
 
 /*
  * Return pointer to node at marker.
diff -urN udev-050.orig/libsysfs/dlist.h udev-050/libsysfs/dlist.h
--- udev-050.orig/libsysfs/dlist.h	2004-12-18 11:53:07 +0600
+++ udev-050/libsysfs/dlist.h	1970-01-01 07:00:00 +0700
@@ -1,205 +0,0 @@
-/*
- * dlist.h
- *
- * Copyright (C) 2003 Eric J Bohm
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-#ifndef _DLIST_H_
-#define _DLIST_H_
-
-/* Double linked list header.
-   
-* navigate your list with DLIST_PREV and DLIST_NEXT.  These are macros
-* so function call overhead is minimized.
-
-* Supports perl style push, pop, shift, unshift list semantics.
-
-* You allocate the data and give dlist the pointer.  If your data is
-* complex set the dlist->del_func to a an appropriate delete using
-* dlist_new_with_delete.  Your delete function must match 
-(void * )(del(void *)
-*Otherwise dlist will just use free.
-
-* NOTE: The small amount of pain involved in doing that allows us to
-* avoid copy in copy out semantics.
-
-* Dlist uses an internal mark pointer to keep track of where you are
-* in the list.
-
-* insert and delete take a directional parameter. Where direction
-* corresponds to the direction in which you want the list to go.
-* true direction corresponded to progressing forward in the last
-* false to regressing in the list.
-* so a dlist_insert(yourlist,item,1) will insert it after the mark
-* so a dlist_insert(yourlist,item,0) will insert it before the mark
-* any insert will move the mark to the new node regardless of the direction.
-
-* Just use the dlist_(insert|delete)_(before|after) macros if you do not want
-* to think about it.
-
-*/
-#include <malloc.h>
-typedef struct dl_node {
-  struct dl_node *prev;
-  struct dl_node *next;
-  void *data;
-} DL_node;
-
-typedef struct dlist {
-  DL_node *marker;
-  unsigned long count;
-  size_t data_size;
-  void (*del_func)(void *);
-  DL_node headnode;
-  DL_node *head;
-} Dlist;
-
-Dlist *dlist_new(size_t datasize);
-Dlist *dlist_new_with_delete(size_t datasize,void (*del_func)(void*));
-void *_dlist_mark_move(Dlist *list,int direction);
-void *dlist_mark(Dlist *);
-void dlist_start(Dlist *);
-void dlist_end(Dlist *);
-void dlist_move(struct dlist *source, struct dlist *dest, struct dl_node *target,int direction);
-void *dlist_insert(Dlist *,void *,int) ;
-
-void *dlist_insert_sorted(struct dlist *list, void *new_elem, int (*sorter)(void *, void *));
-
-void dlist_delete(Dlist *,int);
-
-void dlist_push(Dlist *,void *);
-
-void dlist_unshift(Dlist *,void *);
-void dlist_unshift_sorted(Dlist *,void *,int (*sorter)(void *, void *));
-
-void *dlist_pop(Dlist *);
-
-void *dlist_shift(Dlist *);
-
-void dlist_destroy(Dlist *);
-
-int _dlist_merge(struct dlist *listsource, struct dlist *listdest, unsigned int passcount, int (*compare)(void *, void *));
-
-void *dlist_find_custom(struct dlist *list, void *target, int (*comp)(void *, void *));
-
-void dlist_sort_custom(struct dlist *list, int (*compare)(void *, void *));
-
-
-void _dlist_swap(struct dlist *list, struct dl_node *a, struct dl_node *b);
-
-void dlist_transform(struct dlist *list, void (*node_operation)(void *));
-
-
-/* 
- * _dlist_remove is for internal use only
- * _dlist_mark_move is for internal use only
- */
-void *_dlist_remove(struct dlist *,struct dl_node *,int );
-void *_dlist_insert_dlnode(struct dlist *list,struct dl_node *new_node,int direction);
-
-#define dlist_prev(A) _dlist_mark_move((A),0)
-#define dlist_next(A) _dlist_mark_move((A),1)
-
-#define dlist_insert_before(A,B) dlist_insert((A),(B),0)
-#define dlist_insert_after(A,B) dlist_insert((A),(B),1)
-
-#define dlist_delete_before(A) dlist_delete((A),0)
-#define dlist_delete_after(A) dlist_delete((A),1)
-
-/**
- * provide for loop header which iterates the mark from start to end
- * list: the dlist pointer, use dlist_mark(list) to get iterator
- */
-#define dlist_for_each(list) \
-	for(dlist_start(list),dlist_next(list); \
-		(list)->marker!=(list)->head;dlist_next(list))
-
-/**
- * provide for loop header which iterates the mark from end to start
- * list: the dlist pointer, use dlist_mark(list) to get iterator
- */
-#define dlist_for_each_rev(list) \
-	for(dlist_end(list),dlist_prev(list); \
-		(list)->marker!=(list)->head;dlist_prev(list))
-
-/**
- * provide for loop header which iterates through the list without moving mark
- * list: the dlist_pointer
- * iterator: dl_node pointer to iterate
- */
-#define dlist_for_each_nomark(list,iterator) \
-	for((iterator)=(list)->head->next; (iterator)!=(list)->head; \
-		(iterator)=(iterator)->next)
-
-/**
- * provide for loop header which iterates through the list without moving mark
- * in reverse
- * list: the dlist_pointer
- * iterator: dl_node pointer to iterate
- */
-#define dlist_for_each_nomark_rev(list,iterator) \
-	for((iterator)=(list)->head->prev; (iterator)!=(list)->head; \
-		(iterator)=(iterator)->prev)
-/**
- * provide for loop header which iterates through the list providing a
- * data iterator
- * list: the dlist pointer
- * data_iterator: the pointer of type datatype to iterate
- * datatype:  actual type of the contents in the dl_node->data
- */
-
-#define dlist_for_each_data(list,data_iterator,datatype) \
-	for(dlist_start(list), (data_iterator)=(datatype *) dlist_next(list); \
-	(list)->marker!=(list)->head;(data_iterator)=(datatype *) dlist_next(list))
-
-/**
- * provide for loop header which iterates through the list providing a
- * data iterator in reverse
- * list: the dlist pointer
- * data_iterator: the pointer of type datatype to iterate
- * datatype:  actual type of the contents in the dl_node->data
- */
-#define dlist_for_each_data_rev(list,data_iterator,datatype) \
-	for(dlist_end(list), (data_iterator)=(datatype *) dlist_prev(list); \
-	(list)->marker!=(list)->head;(data_iterator)=(datatype *) dlist_prev(list))
-
-/**
- * provide for loop header which iterates through the list providing a
- * data iterator without moving the mark
- * list: the dlist pointer
- * iterator: the dl_node pointer to iterate
- * data_iterator: the pointer of type datatype to iterate
- * datatype:  actual type of the contents in the dl_node->data
- */
-
-#define dlist_for_each_data_nomark(list,iterator,data_iterator,datatype) \
-	for((iterator)=(list)->head->next, (data_iterator)=(datatype *) (iterator)->data; \
-	(iterator)!=(list)->head;(iterator)=(iterator)->next,(data_iterator)=(datatype *) (iterator))
-
-/**
- * provide for loop header which iterates through the list providing a
- * data iterator in reverse without moving the mark
- * list: the dlist pointer
- * iterator: the dl_node pointer to iterate
- * data_iterator: the pointer of type datatype to iterate
- * datatype:  actual type of the contents in the dl_node->data
- */
-#define dlist_for_each_data_nomark_rev(list,iterator, data_iterator,datatype) \
-	for((iterator)=(list)->head->prev, (data_iterator)=(datatype *) (iterator)->data; \
-	(iterator)!=(list)->head;(iterator)=(iterator)->prev,(data_iterator)=(datatype *) (iterator))
-
-#endif /* _DLIST_H_ */
diff -urN udev-050.orig/libsysfs/sysfs/dlist.h udev-050/libsysfs/sysfs/dlist.h
--- udev-050.orig/libsysfs/sysfs/dlist.h	1970-01-01 07:00:00 +0700
+++ udev-050/libsysfs/sysfs/dlist.h	2005-01-02 20:09:11 +0600
@@ -0,0 +1,205 @@
+/*
+ * dlist.h
+ *
+ * Copyright (C) 2003 Eric J Bohm
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef _DLIST_H_
+#define _DLIST_H_
+
+/* Double linked list header.
+   
+* navigate your list with DLIST_PREV and DLIST_NEXT.  These are macros
+* so function call overhead is minimized.
+
+* Supports perl style push, pop, shift, unshift list semantics.
+
+* You allocate the data and give dlist the pointer.  If your data is
+* complex set the dlist->del_func to a an appropriate delete using
+* dlist_new_with_delete.  Your delete function must match 
+(void * )(del(void *)
+*Otherwise dlist will just use free.
+
+* NOTE: The small amount of pain involved in doing that allows us to
+* avoid copy in copy out semantics.
+
+* Dlist uses an internal mark pointer to keep track of where you are
+* in the list.
+
+* insert and delete take a directional parameter. Where direction
+* corresponds to the direction in which you want the list to go.
+* true direction corresponded to progressing forward in the last
+* false to regressing in the list.
+* so a dlist_insert(yourlist,item,1) will insert it after the mark
+* so a dlist_insert(yourlist,item,0) will insert it before the mark
+* any insert will move the mark to the new node regardless of the direction.
+
+* Just use the dlist_(insert|delete)_(before|after) macros if you do not want
+* to think about it.
+
+*/
+#include <malloc.h>
+typedef struct dl_node {
+  struct dl_node *prev;
+  struct dl_node *next;
+  void *data;
+} DL_node;
+
+typedef struct dlist {
+  DL_node *marker;
+  unsigned long count;
+  size_t data_size;
+  void (*del_func)(void *);
+  DL_node headnode;
+  DL_node *head;
+} Dlist;
+
+Dlist *dlist_new(size_t datasize);
+Dlist *dlist_new_with_delete(size_t datasize,void (*del_func)(void*));
+void *_dlist_mark_move(Dlist *list,int direction);
+void *dlist_mark(Dlist *);
+void dlist_start(Dlist *);
+void dlist_end(Dlist *);
+void dlist_move(struct dlist *source, struct dlist *dest, struct dl_node *target,int direction);
+void *dlist_insert(Dlist *,void *,int) ;
+
+void *dlist_insert_sorted(struct dlist *list, void *new_elem, int (*sorter)(void *, void *));
+
+void dlist_delete(Dlist *,int);
+
+void dlist_push(Dlist *,void *);
+
+void dlist_unshift(Dlist *,void *);
+void dlist_unshift_sorted(Dlist *,void *,int (*sorter)(void *, void *));
+
+void *dlist_pop(Dlist *);
+
+void *dlist_shift(Dlist *);
+
+void dlist_destroy(Dlist *);
+
+int _dlist_merge(struct dlist *listsource, struct dlist *listdest, unsigned int passcount, int (*compare)(void *, void *));
+
+void *dlist_find_custom(struct dlist *list, void *target, int (*comp)(void *, void *));
+
+void dlist_sort_custom(struct dlist *list, int (*compare)(void *, void *));
+
+
+void _dlist_swap(struct dlist *list, struct dl_node *a, struct dl_node *b);
+
+void dlist_transform(struct dlist *list, void (*node_operation)(void *));
+
+
+/* 
+ * _dlist_remove is for internal use only
+ * _dlist_mark_move is for internal use only
+ */
+void *_dlist_remove(struct dlist *,struct dl_node *,int );
+void *_dlist_insert_dlnode(struct dlist *list,struct dl_node *new_node,int direction);
+
+#define dlist_prev(A) _dlist_mark_move((A),0)
+#define dlist_next(A) _dlist_mark_move((A),1)
+
+#define dlist_insert_before(A,B) dlist_insert((A),(B),0)
+#define dlist_insert_after(A,B) dlist_insert((A),(B),1)
+
+#define dlist_delete_before(A) dlist_delete((A),0)
+#define dlist_delete_after(A) dlist_delete((A),1)
+
+/**
+ * provide for loop header which iterates the mark from start to end
+ * list: the dlist pointer, use dlist_mark(list) to get iterator
+ */
+#define dlist_for_each(list) \
+	for(dlist_start(list),dlist_next(list); \
+		(list)->marker!=(list)->head;dlist_next(list))
+
+/**
+ * provide for loop header which iterates the mark from end to start
+ * list: the dlist pointer, use dlist_mark(list) to get iterator
+ */
+#define dlist_for_each_rev(list) \
+	for(dlist_end(list),dlist_prev(list); \
+		(list)->marker!=(list)->head;dlist_prev(list))
+
+/**
+ * provide for loop header which iterates through the list without moving mark
+ * list: the dlist_pointer
+ * iterator: dl_node pointer to iterate
+ */
+#define dlist_for_each_nomark(list,iterator) \
+	for((iterator)=(list)->head->next; (iterator)!=(list)->head; \
+		(iterator)=(iterator)->next)
+
+/**
+ * provide for loop header which iterates through the list without moving mark
+ * in reverse
+ * list: the dlist_pointer
+ * iterator: dl_node pointer to iterate
+ */
+#define dlist_for_each_nomark_rev(list,iterator) \
+	for((iterator)=(list)->head->prev; (iterator)!=(list)->head; \
+		(iterator)=(iterator)->prev)
+/**
+ * provide for loop header which iterates through the list providing a
+ * data iterator
+ * list: the dlist pointer
+ * data_iterator: the pointer of type datatype to iterate
+ * datatype:  actual type of the contents in the dl_node->data
+ */
+
+#define dlist_for_each_data(list,data_iterator,datatype) \
+	for(dlist_start(list), (data_iterator)=(datatype *) dlist_next(list); \
+	(list)->marker!=(list)->head;(data_iterator)=(datatype *) dlist_next(list))
+
+/**
+ * provide for loop header which iterates through the list providing a
+ * data iterator in reverse
+ * list: the dlist pointer
+ * data_iterator: the pointer of type datatype to iterate
+ * datatype:  actual type of the contents in the dl_node->data
+ */
+#define dlist_for_each_data_rev(list,data_iterator,datatype) \
+	for(dlist_end(list), (data_iterator)=(datatype *) dlist_prev(list); \
+	(list)->marker!=(list)->head;(data_iterator)=(datatype *) dlist_prev(list))
+
+/**
+ * provide for loop header which iterates through the list providing a
+ * data iterator without moving the mark
+ * list: the dlist pointer
+ * iterator: the dl_node pointer to iterate
+ * data_iterator: the pointer of type datatype to iterate
+ * datatype:  actual type of the contents in the dl_node->data
+ */
+
+#define dlist_for_each_data_nomark(list,iterator,data_iterator,datatype) \
+	for((iterator)=(list)->head->next, (data_iterator)=(datatype *) (iterator)->data; \
+	(iterator)!=(list)->head;(iterator)=(iterator)->next,(data_iterator)=(datatype *) (iterator))
+
+/**
+ * provide for loop header which iterates through the list providing a
+ * data iterator in reverse without moving the mark
+ * list: the dlist pointer
+ * iterator: the dl_node pointer to iterate
+ * data_iterator: the pointer of type datatype to iterate
+ * datatype:  actual type of the contents in the dl_node->data
+ */
+#define dlist_for_each_data_nomark_rev(list,iterator, data_iterator,datatype) \
+	for((iterator)=(list)->head->prev, (data_iterator)=(datatype *) (iterator)->data; \
+	(iterator)!=(list)->head;(iterator)=(iterator)->prev,(data_iterator)=(datatype *) (iterator))
+
+#endif /* _DLIST_H_ */
diff -urN udev-050.orig/libsysfs/sysfs_bus.c udev-050/libsysfs/sysfs_bus.c
--- udev-050.orig/libsysfs/sysfs_bus.c	2004-12-18 11:53:07 +0600
+++ udev-050/libsysfs/sysfs_bus.c	2005-01-02 20:09:11 +0600
@@ -20,7 +20,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#include "libsysfs.h"
+#include "sysfs/libsysfs.h"
 #include "sysfs.h"
 
 static void sysfs_close_dev(void *dev)
diff -urN udev-050.orig/libsysfs/sysfs_class.c udev-050/libsysfs/sysfs_class.c
--- udev-050.orig/libsysfs/sysfs_class.c	2004-12-18 11:53:07 +0600
+++ udev-050/libsysfs/sysfs_class.c	2005-01-02 20:09:11 +0600
@@ -20,7 +20,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#include "libsysfs.h"
+#include "sysfs/libsysfs.h"
 #include "sysfs.h"
 
 static void sysfs_close_cls_dev(void *dev)
diff -urN udev-050.orig/libsysfs/sysfs_device.c udev-050/libsysfs/sysfs_device.c
--- udev-050.orig/libsysfs/sysfs_device.c	2004-12-18 11:53:07 +0600
+++ udev-050/libsysfs/sysfs_device.c	2005-01-02 20:09:11 +0600
@@ -20,7 +20,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#include "libsysfs.h"
+#include "sysfs/libsysfs.h"
 #include "sysfs.h"
 
 /**
diff -urN udev-050.orig/libsysfs/sysfs_dir.c udev-050/libsysfs/sysfs_dir.c
--- udev-050.orig/libsysfs/sysfs_dir.c	2004-12-18 11:53:07 +0600
+++ udev-050/libsysfs/sysfs_dir.c	2005-01-02 20:09:11 +0600
@@ -20,7 +20,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#include "libsysfs.h"
+#include "sysfs/libsysfs.h"
 #include "sysfs.h"
 
 /**
diff -urN udev-050.orig/libsysfs/sysfs_driver.c udev-050/libsysfs/sysfs_driver.c
--- udev-050.orig/libsysfs/sysfs_driver.c	2004-12-18 11:53:07 +0600
+++ udev-050/libsysfs/sysfs_driver.c	2005-01-02 20:09:11 +0600
@@ -20,7 +20,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#include "libsysfs.h"
+#include "sysfs/libsysfs.h"
 #include "sysfs.h"
 
 static void sysfs_close_driver_device(void *device)
diff -urN udev-050.orig/libsysfs/sysfs_utils.c udev-050/libsysfs/sysfs_utils.c
--- udev-050.orig/libsysfs/sysfs_utils.c	2004-12-18 11:53:07 +0600
+++ udev-050/libsysfs/sysfs_utils.c	2005-01-02 20:09:11 +0600
@@ -20,7 +20,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#include "libsysfs.h"
+#include "sysfs/libsysfs.h"
 #include "sysfs.h"
 
 static int sort_char(void *new, void *old)
diff -urN udev-050.orig/Makefile udev-050/Makefile
--- udev-050.orig/Makefile	2004-12-18 11:53:07 +0600
+++ udev-050/Makefile	2005-01-02 22:12:55 +0600
@@ -92,7 +92,11 @@
 RANLIB = $(CROSS)ranlib
 HOSTCC = gcc
 
-export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS ARCH_LIB_OBJS CRT0
+ifeq ($(strip $(SYS_SYSFS)),)
+CPPFLAGS = -I`pwd`/libsysfs
+endif
+
+export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS ARCH_LIB_OBJS CRT0 CPPFLAGS
 
 # code taken from uClibc to determine the current arch
 ARCH := ${shell $(CC) -dumpmachine | sed -e s'/-.*//' -e 's/i.86/i386/' -e 's/sparc.*/sparc/' \
@@ -170,9 +174,6 @@
 	LIB_OBJS += -lselinux
 endif
 
-CFLAGS +=	-I$(PWD)/libsysfs/sysfs \
-		-I$(PWD)/libsysfs
-
 # config files automatically generated
 GEN_CONFIGS =	$(LOCAL_CFG_DIR)/udev.conf
 
@@ -182,6 +183,7 @@
 		$(MAKE) prefix=$(prefix) \
 			LD="$(LD)" \
 			SYSFS="$(SYSFS)" \
+			SYS_SYSFS=$(SYS_SYSFS) \
 			KERNEL_DIR="$(KERNEL_DIR)" \
 			QUIET="$(QUIET)" \
 			-C $$target $@ ; \
@@ -227,11 +229,13 @@
 	namedev.o		\
 	namedev_parse.o
 
-OBJS = \
-	libsysfs/sysfs.a	\
-	udev.a
-
+ifneq ($(strip $(SYS_SYSFS)),)
+LIB_OBJS += $(SYS_SYSFS)
+else
 SYSFS = $(PWD)/libsysfs/sysfs.a
+endif
+
+OBJS = udev.a $(SYSFS)
 
 ifeq ($(strip $(USE_KLIBC)),true)
 	HEADERS	+= \
@@ -258,7 +262,7 @@
 	$(QUIET) $(AR) cq $@ $(UDEV_OBJS)
 	$(QUIET) $(RANLIB) $@
 
-libsysfs/sysfs.a: $(SYSFS_OBJS)
+$(PWD)/libsysfs/sysfs.a: $(SYSFS_OBJS)
 	rm -f $@
 	$(QUIET) $(AR) cq $@ $(SYSFS_OBJS)
 	$(QUIET) $(RANLIB) $@
@@ -331,7 +335,7 @@
 	$(QUIET) $(STRIPCMD) $@
 
 .c.o:
-	$(QUIET) $(CC) $(CFLAGS) -c -o $@ $<
+	$(QUIET) $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 
 clean:
@@ -342,7 +346,7 @@
 	$(MAKE) -C klibc SUBDIRS=klibc clean
 	@extras="$(EXTRAS)" ; for target in $$extras ; do \
 		echo $$target ; \
-		$(MAKE) prefix=$(prefix) LD="$(LD)" SYSFS="$(SYSFS)" \
+		$(MAKE) prefix=$(prefix) LD="$(LD)" SYS_SYSFS=$(SYS_SYSFS) SYSFS="$(SYSFS)" \
 			-C $$target $@ ; \
 	done ; \
 
@@ -437,7 +441,7 @@
 endif
 	@extras="$(EXTRAS)" ; for target in $$extras ; do \
 		echo $$target ; \
-		$(MAKE) prefix=$(prefix) LD="$(LD)" SYSFS="$(SYSFS)" \
+		$(MAKE) prefix=$(prefix) LD="$(LD)" SYS_SYSFS=$(SYS_SYSFS) SYSFS="$(SYSFS)" \
 			-C $$target $@ ; \
 	done ; \
 
@@ -461,7 +465,7 @@
 	- killall $(DAEMON)
 	@extras="$(EXTRAS)" ; for target in $$extras ; do \
 		echo $$target ; \
-		$(MAKE) prefix=$(prefix) LD="$(LD)" SYSFS="$(SYSFS)" \
+		$(MAKE) prefix=$(prefix) LD="$(LD)" SYS_SYSFS=$(SYS_SYSFS) SYSFS="$(SYSFS)" \
 			-C $$target $@ ; \
 	done ; \
 
diff -urN udev-050.orig/namedev.c udev-050/namedev.c
--- udev-050.orig/namedev.c	2004-12-18 11:53:07 +0600
+++ udev-050/namedev.c	2005-01-02 20:09:11 +0600
@@ -32,7 +32,7 @@
 #include <sys/wait.h>
 #include <sys/stat.h>
 
-#include "libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 #include "list.h"
 #include "udev.h"
 #include "udev_utils.h"
diff -urN udev-050.orig/udev_add.c udev-050/udev_add.c
--- udev-050.orig/udev_add.c	2004-12-18 11:53:07 +0600
+++ udev-050/udev_add.c	2005-01-02 20:09:11 +0600
@@ -36,7 +36,7 @@
 #include <linux/sockios.h>
 #include <pwd.h>
 
-#include "libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 #include "udev.h"
 #include "udev_utils.h"
 #include "udev_version.h"
diff -urN udev-050.orig/udev.c udev-050/udev.c
--- udev-050.orig/udev.c	2004-12-18 11:53:07 +0600
+++ udev-050/udev.c	2005-01-02 20:09:11 +0600
@@ -31,7 +31,7 @@
 #include <signal.h>
 #include <unistd.h>
 
-#include "libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 #include "udev.h"
 #include "udev_utils.h"
 #include "udev_sysfs.h"
diff -urN udev-050.orig/udev_config.c udev-050/udev_config.c
--- udev-050.orig/udev_config.c	2004-12-18 11:53:07 +0600
+++ udev-050/udev_config.c	2005-01-02 20:09:11 +0600
@@ -32,7 +32,7 @@
 #include <errno.h>
 #include <ctype.h>
 
-#include "libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 #include "udev.h"
 #include "udev_utils.h"
 #include "udev_version.h"
diff -urN udev-050.orig/udev_db.c udev-050/udev_db.c
--- udev-050.orig/udev_db.c	2004-12-18 11:53:07 +0600
+++ udev-050/udev_db.c	2005-01-02 20:09:11 +0600
@@ -31,7 +31,7 @@
 #include <errno.h>
 #include <dirent.h>
 
-#include "libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 #include "udev.h"
 #include "udev_utils.h"
 #include "logging.h"
diff -urN udev-050.orig/udev.h udev-050/udev.h
--- udev-050.orig/udev.h	2004-12-18 11:53:07 +0600
+++ udev-050/udev.h	2005-01-02 20:09:11 +0600
@@ -24,7 +24,7 @@
 #define _UDEV_H_
 
 #include <sys/param.h>
-#include "libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 
 #define ALARM_TIMEOUT			120
 #define COMMENT_CHARACTER		'#'
diff -urN udev-050.orig/udevinfo.c udev-050/udevinfo.c
--- udev-050.orig/udevinfo.c	2004-12-18 11:53:07 +0600
+++ udev-050/udevinfo.c	2005-01-02 20:09:11 +0600
@@ -27,8 +27,8 @@
 #include <unistd.h>
 #include <errno.h>
 
-#include "libsysfs/sysfs/libsysfs.h"
-#include "libsysfs/dlist.h"
+#include <sysfs/libsysfs.h>
+#include <sysfs/dlist.h>
 #include "udev.h"
 #include "udev_utils.h"
 #include "udev_version.h"
diff -urN udev-050.orig/udev_start.c udev-050/udev_start.c
--- udev-050.orig/udev_start.c	2004-12-18 11:53:07 +0600
+++ udev-050/udev_start.c	2005-01-02 20:09:11 +0600
@@ -33,7 +33,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 #include "logging.h"
 #include "udev_utils.h"
 #include "list.h"
diff -urN udev-050.orig/udev_sysfs.c udev-050/udev_sysfs.c
--- udev-050.orig/udev_sysfs.c	2004-12-18 11:53:07 +0600
+++ udev-050/udev_sysfs.c	2005-01-02 20:09:11 +0600
@@ -28,7 +28,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 
-#include "libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 #include "udev_version.h"
 #include "udev_sysfs.h"
 #include "udev_utils.h"
diff -urN udev-050.orig/udev_sysfs.h udev-050/udev_sysfs.h
--- udev-050.orig/udev_sysfs.h	2004-12-18 11:53:07 +0600
+++ udev-050/udev_sysfs.h	2005-01-02 20:09:11 +0600
@@ -22,7 +22,7 @@
 #ifndef _UDEV_SYSFS_H_
 #define _UDEV_SYSFS_H_
 
-#include "libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 
 #define WAIT_MAX_SECONDS		5
 #define WAIT_LOOP_PER_SECOND		20
diff -urN udev-050.orig/udevtest.c udev-050/udevtest.c
--- udev-050.orig/udevtest.c	2004-12-18 11:53:07 +0600
+++ udev-050/udevtest.c	2005-01-02 20:09:11 +0600
@@ -27,7 +27,7 @@
 #include <ctype.h>
 #include <signal.h>
 
-#include "libsysfs/sysfs/libsysfs.h"
+#include <sysfs/libsysfs.h>
 #include "udev.h"
 #include "udev_sysfs.h"
 #include "udev_utils.h"

[-- Attachment #9: udev-0.46-alt-efmt_fixes.patch --]
[-- Type: text/x-patch, Size: 5002 bytes --]

diff -urN udev-046.orig/namedev.c udev-046/namedev.c
--- udev-046.orig/namedev.c	2004-12-28 02:43:18 +0600
+++ udev-046/namedev.c	2004-12-28 02:43:54 +0600
@@ -184,13 +184,13 @@
  *  @param  name                Name to check for
  *  @return                     0 if <name> didn't exist and N otherwise.
  */
-static int find_free_number(struct udevice *udev, const char *name)
+static int find_free_number(struct udevice *udev, const char *name, const char *tail)
 {
 	char filename[NAME_SIZE];
 	int num = 0;
 	struct udevice db_udev;
 
-	strfieldcpy(filename, name);
+	snprintf(filename, NAME_SIZE, "%s%s", name, tail);
 	while (1) {
 		dbg("look for existing node '%s'", filename);
 		memset(&db_udev, 0x00, sizeof(struct udevice));
@@ -204,14 +204,18 @@
 			info("find_free_number gone crazy (num=%d), aborted", num);
 			return -1;
 		}
-		snprintf(filename, NAME_SIZE, "%s%d", name, num);
+		snprintf(filename, NAME_SIZE, "%s%d%s", name, num, tail);
 		filename[NAME_SIZE-1] = '\0';
 	}
 }
 
 static void apply_format(struct udevice *udev, char *string, size_t maxsize,
 			 struct sysfs_class_device *class_dev,
-			 struct sysfs_device *sysfs_device)
+			 struct sysfs_device *sysfs_device);
+
+static void apply_format_token(struct udevice *udev, char *string, size_t maxsize,
+			       struct sysfs_class_device *class_dev,
+			       struct sysfs_device *sysfs_device, int use_ext)
 {
 	char temp[NAME_SIZE];
 	char temp2[NAME_SIZE];
@@ -291,12 +295,12 @@
 					strfieldcpy(temp2, spos);
 				else
 					strfieldcpymax(temp2, spos, slen+1);
-				strfieldcatmax(string, temp2, maxsize);
-				dbg("substitute part of result string '%s'", temp2);
 			} else {
-				strfieldcatmax(string, udev->program_result, maxsize);
-				dbg("substitute result string '%s'", udev->program_result);
+				strfieldcpy(temp2, udev->program_result);
 			}
+			apply_format(udev, temp2, NAME_SIZE, class_dev, sysfs_device);
+			strfieldcatmax(string, temp2, maxsize);
+			dbg("substitute part of result string '%s'", temp2);
 			break;
 		case 's':
 			if (attr != NULL) {
@@ -327,12 +331,19 @@
 			pos++;
 			break;
 		case 'e':
-			next_free_number = find_free_number(udev, string);
+			if (!use_ext) {
+				dbg("prohibited usage of attribute %%e");
+				break;
+			}
+			/* prohibite "extended" attributes in tail */
+			apply_format_token(udev, tail, NAME_SIZE, class_dev, sysfs_device, 0);
+			next_free_number = find_free_number(udev, string, tail);
 			if (next_free_number > 0) {
 				sprintf(temp2, "%d", next_free_number);
 				strfieldcatmax(string, temp2, maxsize);
 			}
-			break;
+			strfieldcatmax(string, tail, maxsize);
+			return;
 		default:
 			dbg("unknown substitution type '%%%c'", c);
 			break;
@@ -345,6 +356,67 @@
 	}
 }
 
+#define declare_string_size(strname, strsize) char (strname)[strsize]
+/* A decimal number can't be more then 30 symbols wide */
+#define maxint_digits 30
+static void apply_format(struct udevice *udev, char *string, size_t maxsize,
+			 struct sysfs_class_device *class_dev,
+			 struct sysfs_device *sysfs_device)
+{
+	int consumed;
+	char *tokenptr;
+	size_t tokenspace;
+	size_t tokenlen;
+	char *stringptr = string;
+	char sscanf_ptrn[5 + maxint_digits];
+	declare_string_size(token, maxsize);
+	snprintf(sscanf_ptrn, 5 + maxint_digits, "%%%ds%%n", maxsize - 1);
+	tokenptr = token;
+	tokenptr[0] = '\0';
+	tokenspace = maxsize;
+	while (0 < sscanf(stringptr, sscanf_ptrn, tokenptr, &consumed)) {
+		/* next token now has been put into 'token'
+		 * let's process it...
+		 */
+		apply_format_token(udev, tokenptr, tokenspace, class_dev, sysfs_device, 1);
+
+		/* Now we need to add a trailing whitespace to the
+		 * processed token and advance to the next string's
+		 * token...
+		 */
+		stringptr += consumed;
+		tokenlen = strlen(tokenptr);
+		/* hopefully I didn't make a mistake in bound
+		 * checks... tokenlen is always less than tokenspace
+		 * at least by one. But we need to check if there's a
+		 * space for additional whitespace and next token
+		 * (i.e. tokenlen must be at least 3 bytes less than
+		 * tokenspace). Additionally we should prevent int
+		 * overflow errors...
+		 */
+		if (tokenspace < 3 || tokenspace - 3 <= tokenlen) {
+			if (*stringptr)
+				dbg("Space exhausted while some trailing data left in format string");
+			break;
+		}
+		strncat(tokenptr + tokenlen, " ", tokenspace - tokenlen - 1);
+		tokenptr += tokenlen + 1;
+		tokenspace -= tokenlen + 1;
+		/* and finally adjust sscanf_ptrn to prevent buffer
+		 * overflow in sscanf
+		 */
+		snprintf(sscanf_ptrn, 5 + maxint_digits, "%%%ds%%n", tokenspace - 1);
+	}
+	/* remove leading and trailing whitespace. They do matter sometimes */
+	for(tokenptr = token;isspace(*tokenptr);tokenptr++);
+	tokenlen = strlen(tokenptr);
+	if (tokenlen > 0)
+		tokenptr[tokenlen - 1] = '\0';
+	strncpy(string, tokenptr, maxsize);
+}
+#undef declare_string_size
+#undef maxint_digits
+
 static void fix_kernel_name(struct udevice *udev)
 {
 	char *temp = udev->kernel_name;

             reply	other threads:[~2005-01-07 17:07 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-01-07 17:07 Alexey Morozov [this message]
2005-01-08  5:11 ` Several fixes and enhancements for extented naming rules Kay Sievers
2005-01-08  8:34 ` Several fixes and enhancements for extented naming rules parameters Alexey Morozov
2005-01-08 14:53 ` Several fixes and enhancements for extented naming Kay Sievers
2005-01-10  8:37 ` Several fixes and enhancements for extented naming rules parameters Alexey Morozov
2005-01-10 12:03 ` Several fixes and enhancements for extented naming rules Kay Sievers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=41DEC1E2.3060806@idisys.iae.nsk.su \
    --to=alex-hp@idisys.iae.nsk.su \
    --cc=linux-hotplug@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).