Saturday Oct 03, 2009

New in 124: physical eject button

OpenSolaris build 124 is out and includes a new feature: now you can use the eject button on your CD/DVD drive to eject the disc, even if it is mounted. To quote the heads-up message:

Pressing Eject button on CD/DVD drive's front panel will have the same effect as typing 'eject' in the terminal or clicking the corresponding GUI icon in the File Browser. Most modern drives support this feature, though some older ones don't.

You may see a harmless pop-up message "Unable to unmount volume" due to GNOME bug 9805. It can be safely ignored, but if it bothers you, the workaround is:

svccfg -s rmvolmgr setprop rmvolmgr/eject_button=boolean: false svcadm restart rmvolmgr

The side effect of the workaround is being able to use physical eject button only with a GNOME session running, not when logged into the text console.

Aside from the issues listed in the build notes, be aware of the "Console User" problems. If you are curious about how the eject button works in OpenSolaris, read ARC case 2009/058.

It is quite remarkable that Solaris managed to go without this capability for so long: other OSes have had it for years. I should have fixed it as part of the Tamarack project, but had to sacrifice some features to meet the schedule. I then switched to networking projects, and the feeling of unfinished business has been nagging me ever since.

Walking around with a solution to a problem in your head is, I imagine, not unlike being pregnant: you cannot carry it inside forever. I knew how, I had the code visualized mentally. It was a great relief when one evening I finally initiated the mind->computer transfer. The hard part was to properly test the code: too much weird or buggy hardware out there. All of the PCs, x86 laptops and recent Sun products worked just fine. I did encounter some old Sun gear that did not support the eject button - for those, the eject(1M) command continues to be the only option.

I'd like to thank Neal, Phi and Larry for their help with the last mile effort.

Friday Feb 03, 2006

My little Solaris security cheat sheet

This returned me to sanity a few times while learning about Solaris security. Like many others, I'm not a security expert and I often need a short version to fit in my head.

authorization A right assigned to users that is checked by privileged programs to determine whether users can execute restricted functionality. More in auth_attr(4).

privilege An attribute that provides fine-grained control over the actions of processes, as opposed to traditional unix all-or-nothing, super-user vs user, model. More in privileges(5).

profile A logical grouping of authorizations and commands. Profile shells, pf[ck]sh, interpret profiles to form a secure execution environment. More in prof_attr(4), exec_attr(4).

role A type of user account, with associated authorizations and profiles. Roles cannot be logged in directly - users assume roles using su(1M).

how to getCLIAPI

Per-user: all user processes have same authorizations. Per-process: each process has separate privilege sets.
Static: once assigned to user, remains the same. Dynamic: privilege sets can change during process lifecycle.
A simple token. In theory can be easily added to other OSes. Integrated deep into Solaris.
Userland Userland and kernel.
Introduced in Solaris 8 1 Introduced in Solaris 10 1

1Was also available much earlier in Trusted Solaris.


Thursday Sep 08, 2005

Graphing the Solaris kernel

Free Code Graphing Project was an attempt to visualize Linux kernel source code. Now that Solaris is free code, too, why not try to graph it. This blog entry describes my little effort of debugging the thing into existence. I can't afford to spend any more time on this, so hopefully someone picks the baton.

The end result is a huge PostScript file that looks like this:

Sample close-up, common/vm/seg_kmem.c:

Roughly, the algorithm used:

  • Function: sequential code is a line, loop is an arc, branch splits the line.
  • Color: normal functions are blue, static functions are green.
  • File: functions are put in boxes, sorted by size and arranged in a spiral.
  • Ring: Files are put in boxes, sorted by size and arranged in a circle.
  • Rings can be broken into sectors.

Here's how rings are defined for Linux:

RING1:=init lib mm kernel ipc
RING2:=net fs
RING3:=$(subst $(KERNEL_DIR)/,,$(wildcard $(KERNEL_DIR)/arch/\*))
RING4:=drivers crypto sound security

Solaris has a bit different directory structure. Here's what I used:

RING1:=common/os common/vm common/c2 common/cpr common/disp common/dtrace common/exec common/krtld common/syscall
RING2:=common/fs common/inet common/ipp common/ktli common/rpc
RING3:=i86pc sparc sun sun4 sun4u sun4v

Steps to make it work in Solaris

1. Prerequisites:

2. Set you KERNEL_DIR environment variable to usr/src/uts subdirectory of OpenSolaris source, e.g.:

KERNEL_DIR=$HOME/solgraph/usr/src/uts; export KERNEL_DIR

3. Preprocess OpenSolaris code, since the fcgp parser does not like Solaris coding style (ignore warnings):

chmod -R +w $KERNEL_DIR
find $KERNEL_DIR -name '\*.c' -exec indent -npsl {} \\;

4. Modify your path to look in /usr/xpg4/bin first: Alternatively you can replace all 'tail -n number' occurences in fcgp scripts with 'tail -number', but it's easier to just use /usr/xpg4/bin/tail.

PATH=/usr/xpg4/bin:$PATH; export PATH

5. If using X, turn off the bell. Fcgp spits out some escape sequences that would drive you nuts (they might not look pretty on some terminals either):

xset -b

6. Kick off the build process. Takes about 9 minutes on my Ferrari 3400.

cd lgp-2.6.0a-solaris
gmake CC=gcc

7. Generate viewable/printable postscript files. Examples for a single file and for a 6x6 poster:

./posterize a4 1
./posterize a4 6

See README for more information on printing and assembling a poster.

To do list

  • Fix the parser to handle Solaris coding style.
  • Some files, e.g. common/c2/audit_syscalls.c and common/disp/ts.c, are not rendered correctly, resulting in very large bounding boxes. The rest of the files are scaled down too much. This problem might take care of itself when parser is fixed.
  • Replace the Tux in the center of the circle with OpenSolaris logo. See
  • Figure out what's in 'codemap' and 'zoom' directories and make it work.
  • Come up with an easy way to locate files and functions on the map.

I won't have time for these in the next two months, so feel free to pick up where I left. I can be reached at artem dot kachitchkin at sun dot com.


Thursday Jul 14, 2005

A minor instance of driver confusion

Most driver writers are familiar with device minor numbers. But a notion of an instance number is specific to Solaris and it is often incorrectly assumed that minor == instance. Let's see if we can see clear that up.

Instance number

A driver handles devices of a certain type. There can be multiple instances of the same device type in the system. For example, there are two asynchronous serial devices (UARTs) on my system, handled by the asy(7D) driver and represented by two nodes in the device tree:

    $ prtconf -D | grep asy
            asy, instance #0 (driver name: asy)
            asy, instance #1 (driver name: asy)

These are the two instances of the same driver: sharing binary code in the kernel address space, but maintaining separate data 1. Instances are numbered, in this case 0 and 1. Instance numbers are assigned permanently to physical devices in the system; the mapping is maintained in the /etc/path_to_inst file:

    $ grep asy /etc/path_to_inst 
    "/isa/asy@1,3f8" 0 "asy"
    "/isa/asy@1,2f8" 1 "asy"

There are also drivers without respective hardware, called pseudo drivers. An example of a pseudo driver is random(7D), the random number generator driver. Pseudo drivers have no physical device nodes to attach to. We have to synthesize artificial instances via driver.conf file:

    $ cat /kernel/drv/random.conf | egrep -v '\^#|\^$'
    name="random" parent="pseudo" instance=0;

The system obeys and creates a node for instance 0:

    $ prtconf -DP | grep random
            random, instance #0 (driver name: random)

Drivers can retrieve their instance number with ddi_get_instance().

Minor number

Outside the kernel, devices are identified by their {major, minor} pairs, also know as dev_t. The major number range is owned by the system. It assigns major numbers when drivers are installed and keeps the list in /etc/name_to_major:

    $ grep asy /etc/name_to_major
    asy 106

The minor number range is owned by the driver. A minor number becomes visible to the userland when the driver creates a minor node using ddi_create_minor_node() 2, which takes minor number as one of its arguments:

    int ddi_create_minor_node(dev_info_t \*dip, char \*name, int
        spec_type, minor_t minor_num, char \*node_type, int flag);

Problem is, the minor number range is shared among all driver instances, so each instance can only use a subrange. If each instance needs exactly one minor node, then the node's minor number can equal instance number, i.e. the 4th argument in ddi_create_minor_node() is set to instance number.

Things get a bit fancier in case of multiple minor nodes per instance. Serial drivers typically create two nodes per node: one in /dev/term and one in /dev/cua:

$ ls -lL /dev/{term,cua}/[ab]
crw-------   1 uucp     uucp     106, 131072 Jun 29 19:04 /dev/cua/a
crw-------   1 uucp     uucp     106, 131073 Jun 29 19:04 /dev/cua/b
crw-rw-rw-   1 root     sys      106,  0 Jun 29 19:04 /dev/term/a
crw-rw-rw-   1 root     sys      106,  1 Jun 29 19:04 /dev/term/b

106, as we saw earlier, is asy major number. Minor numbers 0 and 131072 (0x20000) belong to instance 0, and 1 and 131073 (0x20001) to instance 1. The instance/minor mapping is not 1:1 here.


The driver holds the algorithm for mapping instances into minors and vice versa. When the kernel needs to find out instance number from a minor number, it has to ask the driver by calling getinfo(9E) entry point with the DDI_INFO_DEVT2INSTANCE command. One example could be found in spec_open() which calls e_ddi_hold_devi_by_dev().

1 Per-instance data is called soft state and explicitly supported in DDI, see ddi_soft_state(9F) man page.

2 A whole lot of action can be triggered by ddi_create_minor_node(). See dacfc_match_create_minor() and /etc/dacf.conf file on your nearest Solaris system.





Top Tags
« March 2015