ls -lの表示を変えてみる

Head First C 読書会#01 - 名古屋C言語勉強会 | Doorkeeperの時間で、ls -lの表示を変えてみたので、その記録を。 パーミッション表示を755みたいな感じになるようにしてみました。

まずは、ls.cより、ls -lのオプションを処理している所を探す。

1644   while (true)
1645     {
1646       int oi = -1;
1647       int c = getopt_long (argc, argv,
1648                            "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1",
1649                            long_options, &oi);
1650       if (c == -1)
1651         break;
1652
1653       switch (c)
1654         {

1706         case 'l':
1707           format = long_format;
1708           break;

よりlオプションを指定すると、long_formatとなるようです。 色々あさった結果、

3613     case long_format:
3614       for (i = 0; i < cwd_n_used; i++)
3615         {
3616           set_normal_color ();
3617           print_long_format (sorted_file[i]);
3618           DIRED_PUTCHAR ('\n');
3619         }

で呼ばれている print_long_format で1ラインを表示していました。

3782 /* Print information about F in long format.  */
3783 static void
3784 print_long_format (const struct fileinfo *f)
3785 {
・・・
3803   if (f->stat_ok)
3804     filemodestring (&f->stat, modebuf);
3805   else
3806     {
3807       modebuf[0] = filetype_letter[f->filetype];
3808       memset (modebuf + 1, '?', 10);
3809       modebuf[11] = '\0';
3810     }

printfを間に挟みつつ探った結果、filemodestring内でmodebufにパーミッション部分が格納されている事が分かりました。 filemodestringは、filemode.cというcoreutilsとはまた別のファイルで定義されています。

165 void
166 filemodestring (struct stat const *statp, char *str)
167 {
168   strmode (statp->st_mode, str);
169
170   if (S_TYPEISSEM (statp))
171     str[0] = 'F';
172   else if (IS_MIGRATED_FILE (statp))
173     str[0] = 'M';
174   else if (S_TYPEISMQ (statp))
175     str[0] = 'Q';
176   else if (S_TYPEISSHM (statp))
177     str[0] = 'S';
178   else if (S_TYPEISTMO (statp))
179     str[0] = 'T';
180 }

これを下記に書き換えたら、一応狙い通りいけました。

121 void
122 mystrmode (mode_t mode, char *str)
123 {
124   char c;
125
126   c = '0';
127   c += mode & S_IRUSR ? 4 : 0;
128   c += mode & S_IWUSR ? 2 : 0;
129   c += (mode & S_ISUID
130             ? (mode & S_IXUSR ? 0 : 0)
131             : (mode & S_IXUSR ? 1 : 0));
132   str[0] = c;
133
134   c = '0';
135   c += mode & S_IRGRP ? 4 : 0;
136   c += mode & S_IWGRP ? 2 : 0;
137   c += (mode & S_ISGID
138             ? (mode & S_IXGRP ? 0 : 0)
139             : (mode & S_IXGRP ? 1 : 0));
140   str[1] = c;
141
142   c = '0';
143   c += mode & S_IROTH ? 4 : 0;
144   c += mode & S_IWOTH ? 2 : 0;
145   c += (mode & S_ISVTX
146             ? (mode & S_IXOTH ? 0 : 0)
147             : (mode & S_IXOTH ? 1 : 0));
148   str[2] = c;
149
150   str[3] = (mode & S_ISUID
151             ? (mode & S_IXUSR ? 's' : 'S')
152             : (mode & S_IXUSR ? ' ' : ' '));
153   str[4] = (mode & S_ISGID
154             ? (mode & S_IXGRP ? 's' : 'S')
155             : (mode & S_IXGRP ? ' ' : ' '));
156   str[5] = (mode & S_ISVTX
157             ? (mode & S_IXOTH ? 't' : 'T')
158             : (mode & S_IXOTH ? ' ' : ' '));
159
160   str[6] = ' ';
161   str[7] = '\0';
162 }
・・・
209 void
210 filemodestring (struct stat const *statp, char *str)
211 {
212   strmode (statp->st_mode, str);
213   mystrmode (statp->st_mode, str);
214

最初、strmodeが#ifdefで無効になっているのに気づかず変更して、変更したのに動かないってハマったのが悔しい。