shortname以及自动挂载

August 18th, 2009 | by vvoody |

一切问题来自我前些天在优盘上搞的移动版的wiki(采用DokuWiki),插上优盘后,直接编辑我的wiki。但是发现有些页面是空白,功能不正常。后来发现是因为某些文件文件名在Linux下挂载后发生了变化,比如:”JSON.php”变成了”json.php”,造成了wiki无法正常运行 -______-!!

/etc/mtab显示有一个选项是shortname=lower,于是顺藤摸瓜google,发现通过手工挂载用参数shortname=mixed就正常。Linux下mount对fat/vfat文件系统(通常就是优盘的文件系统格式)默认挂载参数shortname的值就是lower。其实这个不太好,所有有人给了patch建议改成默认为shortname=mixed,可以看如下代码,更多见LKML里的讨论

diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 8970d8c..f9af501 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -971,7 +971,7 @@  static int parse_options(char *options, int is_vfat, int silent, int *debug,
 	opts->codepage = fat_default_codepage;
 	opts->iocharset = fat_default_iocharset;
 	if (is_vfat) {
-		opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95;
+		opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95;
 		opts->rodir = 0;
 	} else {
 		opts->shortname = 0;

这个shortname参数都是因为有8.3文件名这种东西的存在而存在的,可以参考Wikipedia上的这篇文章
还没完,每次手工挂载太蠢了。所以我想到了HAL,当时觉得可以改变默认的mount挂载参数(但事实不是)。还找到了如下的HAL policy:

<?xml version="1.0" encoding="UTF-8"?>
 
<deviceinfo version="0.2">
  <device>
    <match key="block.is_volume" bool="true">
      <match key="volume.fsusage" string="filesystem">
        <match key="volume.fstype" string="vfat">
          <merge key="volume.policy.mount_option.shortname="
type="string">shortname=mixed</merge>
        </match>
      </match>
    </match>
  </device>
</deviceinfo>

但是没有成功,lshal里看到了 volume.policy.mount_option.shortname= = ‘mixed’ (string) 这样的信息,可是我在Konqueror里打开仍然是以lower挂载的。在cppgx大牛的提醒和google到的这篇文章中,找到了两个原因:

  1. KDE这类DE会自己管理mount参数
  2. volume.policy.mount_option.shortname 这种写法已废弃

对于第一点,你可以在插上优盘后,打开Konqueror,到Storage Media里右击你的优盘盘符,属性里有一个挂载的标签,里面就有一些自定义的参数,其中就有shortname,而且默认就是lower。因此,如果你使用KDE,那么你可以在这个标签里将shortname改成mixed就可以正常显示优盘的文件名了。不过这不是全局的,你换了个优盘后,还得改一下。这些参数保存在~/.kde/share/config/mediamanagerrc

对于第二点,难怪在最新的hal-spec里打死找不到类似的方法。

到这里我才渐渐明白HAL是无法改变mount的挂载参数的,它可以发现硬件,然后提供给上层应用关于硬盘设备的很多信息,比如什么文件系统,可用的挂载参数等。像KDE这种能否自动挂载的,一定是从HAL那儿获得信息,然后有自己的程序去最终挂载设备,然后显示给用户。我很想看看KDE到底是怎么处理这些挂载参数的,所以经过一番长时间的搜索终于找到了相关代码(从没看过KDE代码,也不懂C++,而且觉得KDE网站搜索做的也不太好):
kdebase-3.5.10/kioslave/media/mediamanager/halbackend.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
QStringList HALBackend::mountoptions(const QString &name)
{
    const Medium* medium = m_mediaList.findById(name);
    if (medium && !isInFstab(medium).isNull())
        return QStringList(); // not handled by HAL - fstab entry
 
    KConfig config("mediamanagerrc");
    config.setGroup(name);
 
    char ** array = libhal_device_get_property_strlist(m_halContext, name.latin1(), "volume.mount.valid_options", NULL);
    QMap<QString,bool> valids;
 
    for (int index = 0; array && array[index]; ++index) {
        QString t = array[index];
        if (t.endsWith("="))
            t = t.left(t.length() - 1);
        valids[t] = true;
        kdDebug() << "valid " << t << endl;
    }
    libhal_free_string_array(array);
    QStringList result;
    QString tmp;
 
    QString fstype = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.fstype");
    if (fstype.isNull())
        fstype = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.policy.mount_filesystem");
 
    QString drive_udi = libhal_device_get_property_QString(m_halContext, name.latin1(), "block.storage_device");
 
    bool removable = false;
    if ( !drive_udi.isNull() )
        removable = libhal_device_get_property_bool(m_halContext, drive_udi.latin1(), "storage.removable", NULL)
                     || libhal_device_get_property_bool(m_halContext, drive_udi.latin1(), "storage.hotpluggable", NULL);
 
    config.setGroup(drive_udi);
    bool value = config.readBoolEntry("automount", false);
    config.setGroup(name);
 
    if (libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_blank", NULL)
        || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_vcd", NULL)
        || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_svcd", NULL)
        || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_videodvd", NULL)
        || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.has_audio", NULL))
        value = false;
 
    result << QString("automount=%1").arg(value ? "true" : "false");
 
    if (valids.contains("ro"))
    {
        value = config.readBoolEntry("ro", false);
        tmp = QString("ro=%1").arg(value ? "true" : "false");
        if (fstype != "iso9660") // makes no sense
            result << tmp;
    }
 
    if (valids.contains("quiet"))
    {
        value = config.readBoolEntry("quiet", false);
        tmp = QString("quiet=%1").arg(value ? "true" : "false");
        if (fstype != "iso9660") // makes no sense
            result << tmp;
    }
 
    if (valids.contains("flush"))
    {
        value = config.readBoolEntry("flush", fstype.endsWith("fat"));
        tmp = QString("flush=%1").arg(value ? "true" : "false");
        result << tmp;
    }
 
    if (valids.contains("uid"))
    {
        value = config.readBoolEntry("uid", true);
        tmp = QString("uid=%1").arg(value ? "true" : "false");
        result << tmp;
    }
 
	if ( valids.contains("locale") )
	{
		value = config.readBoolEntry( "locale", true );
		tmp = QString( "locale=%1" ).arg( value ? "true" : "false" );
		result << tmp;
	}
 
    if (valids.contains("utf8"))
    {
        value = config.readBoolEntry("utf8", true);
        tmp = QString("utf8=%1").arg(value ? "true" : "false");
        result << tmp;
    }
 
    if (valids.contains("shortname"))
    {
        QString svalue = config.readEntry("shortname", "lower").lower();
        if (svalue == "winnt")
            result << "shortname=winnt";
        else if (svalue == "win95")
            result << "shortname=win95";
        else if (svalue == "mixed")
            result << "shortname=mixed";
        else
            result << "shortname=lower";
    }
 
    if (valids.contains("sync"))
    {
        value = config.readBoolEntry("sync", ( valids.contains("flush") && !fstype.endsWith("fat") ) && removable);
        tmp = QString("sync=%1").arg(value ? "true" : "false");
        if (fstype != "iso9660") // makes no sense
            result << tmp;
    }
 
    if (valids.contains("noatime"))
    {
        value = config.readBoolEntry("atime", !fstype.endsWith("fat"));
        tmp = QString("atime=%1").arg(value ? "true" : "false");
        if (fstype != "iso9660") // makes no sense
            result << tmp;
    }
 
    QString mount_point = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.mount_point");
    if (mount_point.isEmpty())
        mount_point = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.policy.desired_mount_point");
 
    mount_point = config.readEntry("mountpoint", mount_point);
 
    if (!mount_point.startsWith("/"))
        mount_point = "/media/" + mount_point;
 
    result << QString("mountpoint=%1").arg(mount_point);
    result << QString("filesystem=%1").arg(fstype);
 
    if (valids.contains("data"))
    {
        QString svalue = config.readEntry("journaling").lower();
        if (svalue == "ordered")
            result << "journaling=ordered";
        else if (svalue == "writeback")
            result << "journaling=writeback";
        else if (svalue == "data")
            result << "journaling=data";
        else
            result << "journaling=ordered";
    }
 
    return result;
}

第10行就是获取HAL提供的有效参数(lshal | grep valid_options);
第13到19行的for循环将各个参数放到valids数组中;
第21行的QStringList result;是所有参数/值对列表;
第92行就是和shortname有关的了。它先是读取配置文件~/.kde/share/config/mediamanagerrc中某个设备的shortname参数值,如果没有默认就是lower。看来KDE里处理shortname也是如此。

不过从上述代码来看,提供给KDE配置mount参数仍然不是很多,比如dmask、fmask等都没有。通过HAL还是可以添加所有的参数到valid_options。

* BTW,上述代码是KDE 3.5.10环境下的,KDE 4默认的shortname已经是mixed了。不过不再是mediamanager了,相关代码还没找到去看。

最后提供个方法修改mount任意挂载参数,以挂载vfat文件系统为例:

$ cat /sbin/mount.vfat
#!/bin/sh
/sbin/mount -i -t vfat -o umask=0000,fmask=0111,dmask=0000,shortname=mixed "$@"

注意,这是全局修改vfat的挂载参数。KDE最后还是调用mount挂载的设备,因此有了这个文件你就可以自定义KDE等不支持的参数了。

EOF

  1. 4 Responses to “shortname以及自动挂载”

  2. By slackcode on Oct 21, 2009

    Internet Explorer 6.0 Windows XP Internet Explorer 6.0 Windows XP

    你的高亮怎么弄上去的?

    Reply

    vvoody Reply:

    Opera 9.80 Windows XP

    wordpress的语法高亮插件 http://wordpress.org/extend/plugins/wp-syntax/

    Reply

    slackcode Reply:

    Mozilla Firefox 3.5.3 Windows XP

    我觉得这个插件好像有点问题似的,我现在换了Typecho了

    Reply

    vvoody Reply:

    Mozilla Firefox 3.5.3 Linux

    Typecho是feelinglucky他们的项目吧?不是wordpress了啊。这个wp-syntax还发现大的问题,基本代码加亮都正常。

    Reply

Post a Comment