Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 drivers/base/class.c   |   34 ++++++++++++++++++++++++++++++++++
 drivers/block/genhd.c  |   25 +++++++++++++++++++++++++
 fs/partitions/check.c  |   27 +++++++++++++++++++++++++++
 include/linux/device.h |    1 +
 4 files changed, 87 insertions(+)

diff -puN drivers/base/class.c~gregkh-driver-driver-sample.sh drivers/base/class.c
--- devel/drivers/base/class.c~gregkh-driver-driver-sample.sh	2005-09-07 20:10:03.000000000 -0700
+++ devel-akpm/drivers/base/class.c	2005-09-07 20:10:03.000000000 -0700
@@ -17,6 +17,7 @@
 #include <linux/string.h>
 #include <linux/kdev_t.h>
 #include <linux/err.h>
+#include <linux/mount.h>
 #include "base.h"
 
 #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
@@ -443,6 +444,24 @@ static ssize_t show_dev(struct class_dev
 	return print_dev_t(buf, class_dev->devt);
 }
 
+static ssize_t show_sample(struct class_device *class_dev, char *buf)
+{
+	const char * context = "system_u:object_r:fixed_disk_device_t";
+	struct vfsmount *mnt;
+	int n;
+
+	n = sprintf(buf, "#!/bin/sh\nmknod ");
+
+	mnt = do_kern_mount("selinuxfs", 0, "selinuxfs", NULL);
+	if (!IS_ERR(mnt)) {
+		mntput(mnt);
+		n += sprintf(buf+n, "-Z %s ", context);
+	}
+	n += sprintf(buf+n, "/dev/%s c %d %d\n", kobject_name(&class_dev->kobj),
+		     MAJOR(class_dev->devt), MINOR(class_dev->devt));
+
+	return n;
+}
 void class_device_initialize(struct class_device *class_dev)
 {
 	kobj_set_kset_s(class_dev, class_obj_subsys);
@@ -514,6 +533,21 @@ int class_device_add(struct class_device
 		attr->store = NULL;
 		class_device_create_file(class_dev, attr);
 		class_dev->devt_attr = attr;
+
+		attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+		if (!attr) {
+			error = -ENOMEM;
+			kobject_del(&class_dev->kobj);
+			goto register_done;
+		}
+		memset(attr, sizeof(*attr), 0x00);
+		attr->attr.name = "sample.sh";
+		attr->attr.mode = S_IRUSR | S_IXUSR | S_IRUGO;
+		attr->attr.owner = parent->owner;
+		attr->show = show_sample;
+		attr->store = NULL;
+		class_device_create_file(class_dev, attr);
+		class_dev->sample_attr = attr;
 	}
 
 	class_device_add_attrs(class_dev);
diff -puN drivers/block/genhd.c~gregkh-driver-driver-sample.sh drivers/block/genhd.c
--- devel/drivers/block/genhd.c~gregkh-driver-driver-sample.sh	2005-09-07 20:10:03.000000000 -0700
+++ devel-akpm/drivers/block/genhd.c	2005-09-07 20:10:03.000000000 -0700
@@ -15,6 +15,7 @@
 #include <linux/kmod.h>
 #include <linux/kobj_map.h>
 #include <linux/buffer_head.h>
+#include <linux/mount.h>
 
 #define MAX_PROBE_HASH 255	/* random */
 
@@ -382,6 +383,25 @@ static ssize_t disk_stats_read(struct ge
 		jiffies_to_msecs(disk_stat_read(disk, io_ticks)),
 		jiffies_to_msecs(disk_stat_read(disk, time_in_queue)));
 }
+static ssize_t disk_sample_read(struct gendisk * disk, char *page)
+{
+	char buf[BDEVNAME_SIZE];
+	const char * context = "system_u:object_r:fixed_disk_device_t";
+	struct vfsmount *mnt;
+	int n;
+
+	n = sprintf(page, "#!/bin/sh\nmknod ");
+
+	mnt = do_kern_mount("selinuxfs", 0, "selinuxfs", NULL);
+	if (!IS_ERR(mnt)) {
+		mntput(mnt);
+		n += sprintf(page+n, "-Z %s ", context);
+	}
+	n += sprintf(page+n, "/dev/%s b %d %d\n", disk_name(disk, 0, buf),
+		disk->major, disk->first_minor);
+
+	return n;
+}
 static struct disk_attribute disk_attr_dev = {
 	.attr = {.name = "dev", .mode = S_IRUGO },
 	.show	= disk_dev_read
@@ -402,6 +422,10 @@ static struct disk_attribute disk_attr_s
 	.attr = {.name = "stat", .mode = S_IRUGO },
 	.show	= disk_stats_read
 };
+static struct disk_attribute disk_attr_sample = {
+	.attr = {.name = "sample.sh", .mode = S_IRUSR | S_IXUSR | S_IRUGO },
+	.show	= disk_sample_read
+};
 
 static struct attribute * default_attrs[] = {
 	&disk_attr_dev.attr,
@@ -409,6 +433,7 @@ static struct attribute * default_attrs[
 	&disk_attr_removable.attr,
 	&disk_attr_size.attr,
 	&disk_attr_stat.attr,
+	&disk_attr_sample.attr,
 	NULL,
 };
 
diff -puN fs/partitions/check.c~gregkh-driver-driver-sample.sh fs/partitions/check.c
--- devel/fs/partitions/check.c~gregkh-driver-driver-sample.sh	2005-09-07 20:10:03.000000000 -0700
+++ devel-akpm/fs/partitions/check.c	2005-09-07 20:10:03.000000000 -0700
@@ -36,6 +36,8 @@
 #include "ultrix.h"
 #include "efi.h"
 
+#include <linux/mount.h>
+
 #ifdef CONFIG_BLK_DEV_MD
 extern void md_autodetect_dev(dev_t dev);
 #endif
@@ -229,6 +231,26 @@ static ssize_t part_stat_read(struct hd_
 		       p->reads, (unsigned long long)p->read_sectors,
 		       p->writes, (unsigned long long)p->write_sectors);
 }
+static ssize_t part_sample_read(struct hd_struct * p, char *page)
+{
+	struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
+	char buf[BDEVNAME_SIZE];
+	const char * context = "system_u:object_r:fixed_disk_device_t";
+	struct vfsmount *mnt;
+	int n;
+
+	n = sprintf(page, "#!/bin/sh\nmknod ");
+
+	mnt = do_kern_mount("selinuxfs", 0, "selinuxfs", NULL);
+	if (!IS_ERR(mnt)) {
+		mntput(mnt);
+		n += sprintf(page+n, "-Z %s ", context);
+	}
+	n += sprintf(page+n, "/dev/%s b %d %d\n", disk_name(disk, p->partno, buf),
+		disk->major, disk->first_minor + p->partno);
+
+	return n;
+}
 static struct part_attribute part_attr_dev = {
 	.attr = {.name = "dev", .mode = S_IRUGO },
 	.show	= part_dev_read
@@ -245,12 +267,17 @@ static struct part_attribute part_attr_s
 	.attr = {.name = "stat", .mode = S_IRUGO },
 	.show	= part_stat_read
 };
+static struct part_attribute part_attr_sample = {
+	.attr = {.name = "sample.sh", .mode = S_IRUSR | S_IXUSR | S_IRUGO },
+	.show	= part_sample_read
+};
 
 static struct attribute * default_attrs[] = {
 	&part_attr_dev.attr,
 	&part_attr_start.attr,
 	&part_attr_size.attr,
 	&part_attr_stat.attr,
+	&part_attr_sample.attr,
 	NULL,
 };
 
diff -puN include/linux/device.h~gregkh-driver-driver-sample.sh include/linux/device.h
--- devel/include/linux/device.h~gregkh-driver-driver-sample.sh	2005-09-07 20:10:03.000000000 -0700
+++ devel-akpm/include/linux/device.h	2005-09-07 20:10:03.000000000 -0700
@@ -198,6 +198,7 @@ struct class_device {
 	struct class		* class;	/* required */
 	dev_t			devt;		/* dev_t, creates the sysfs "dev" */
 	struct class_device_attribute *devt_attr;
+	struct class_device_attribute *sample_attr;
 	struct device		* dev;		/* not necessary, but nice to have */
 	void			* class_data;	/* class-specific data */
 
_