1 # -*- coding: utf-8 -*-
2 #############################################################################
5 # Author : Frederic Lepied
6 # Created on : Mon Oct 4 19:32:49 1999
7 # Version : $Id: FilesCheck.py 1894 2011-11-24 21:56:18Z scop $
8 # Purpose : test various aspects on files: locations, owner, groups,
9 # permission, setuid, setgid...
10 #############################################################################
12 from datetime import datetime
21 from Filter import addDetails, printError, printWarning
22 from Pkg import catcmd, is_utf8, is_utf8_str
27 # must be kept in sync with the filesystem package
66 '/etc/susehelp.d/htdig',
68 '/etc/sysconfig/SuSEfirewall2.d',
69 '/etc/sysconfig/SuSEfirewall2.d/services',
70 '/etc/sysconfig/network',
71 '/etc/sysconfig/network/if-down.d',
72 '/etc/sysconfig/network/if-up.d',
73 '/etc/sysconfig/network/providers',
74 '/etc/sysconfig/network/scripts',
75 '/etc/sysconfig/scripts',
116 '/usr/i586-suse-linux',
117 '/usr/i586-suse-linux/bin',
118 '/usr/i586-suse-linux/include',
119 '/usr/i586-suse-linux/lib',
124 '/usr/lib/browser-plugins',
127 '/usr/lib/pkgconfig',
130 '/usr/lib64/browser-plugins',
133 '/usr/lib64/pkgconfig',
137 '/usr/local/include',
141 '/usr/local/man/man1',
142 '/usr/local/man/man2',
143 '/usr/local/man/man3',
144 '/usr/local/man/man4',
145 '/usr/local/man/man5',
146 '/usr/local/man/man6',
147 '/usr/local/man/man7',
148 '/usr/local/man/man8',
149 '/usr/local/man/man9',
150 '/usr/local/man/mann',
156 '/usr/share/applications',
159 '/usr/share/doc/packages',
166 '/usr/share/locale/aa',
167 '/usr/share/locale/aa/LC_MESSAGES',
168 '/usr/share/locale/af',
169 '/usr/share/locale/af/LC_MESSAGES',
170 '/usr/share/locale/am',
171 '/usr/share/locale/am/LC_MESSAGES',
172 '/usr/share/locale/ang',
173 '/usr/share/locale/ang/LC_MESSAGES',
174 '/usr/share/locale/ar',
175 '/usr/share/locale/ar/LC_MESSAGES',
176 '/usr/share/locale/as',
177 '/usr/share/locale/as/LC_MESSAGES',
178 '/usr/share/locale/az',
179 '/usr/share/locale/az/LC_MESSAGES',
180 '/usr/share/locale/az_IR',
181 '/usr/share/locale/az_IR/LC_MESSAGES',
182 '/usr/share/locale/be',
183 '/usr/share/locale/be/LC_MESSAGES',
184 '/usr/share/locale/be@latin',
185 '/usr/share/locale/be@latin/LC_MESSAGES',
186 '/usr/share/locale/bg',
187 '/usr/share/locale/bg/LC_MESSAGES',
188 '/usr/share/locale/bn',
189 '/usr/share/locale/bn/LC_MESSAGES',
190 '/usr/share/locale/bn_IN',
191 '/usr/share/locale/bn_IN/LC_MESSAGES',
192 '/usr/share/locale/bo',
193 '/usr/share/locale/bo/LC_MESSAGES',
194 '/usr/share/locale/br',
195 '/usr/share/locale/br/LC_MESSAGES',
196 '/usr/share/locale/bs',
197 '/usr/share/locale/bs/LC_MESSAGES',
198 '/usr/share/locale/byn',
199 '/usr/share/locale/byn/LC_MESSAGES',
200 '/usr/share/locale/ca',
201 '/usr/share/locale/ca/LC_MESSAGES',
202 '/usr/share/locale/ca@valencia',
203 '/usr/share/locale/ca@valencia/LC_MESSAGES',
204 '/usr/share/locale/cs',
205 '/usr/share/locale/cs/LC_MESSAGES',
206 '/usr/share/locale/cs_CZ',
207 '/usr/share/locale/cs_CZ/LC_MESSAGES',
208 '/usr/share/locale/cy',
209 '/usr/share/locale/cy/LC_MESSAGES',
210 '/usr/share/locale/da',
211 '/usr/share/locale/da/LC_MESSAGES',
212 '/usr/share/locale/de',
213 '/usr/share/locale/de/LC_MESSAGES',
214 '/usr/share/locale/de_AT',
215 '/usr/share/locale/de_AT/LC_MESSAGES',
216 '/usr/share/locale/de_CH',
217 '/usr/share/locale/de_CH/LC_MESSAGES',
218 '/usr/share/locale/de_DE',
219 '/usr/share/locale/de_DE/LC_MESSAGES',
220 '/usr/share/locale/dv',
221 '/usr/share/locale/dv/LC_MESSAGES',
222 '/usr/share/locale/dz',
223 '/usr/share/locale/dz/LC_MESSAGES',
224 '/usr/share/locale/ee',
225 '/usr/share/locale/ee/LC_MESSAGES',
226 '/usr/share/locale/el',
227 '/usr/share/locale/el/LC_MESSAGES',
228 '/usr/share/locale/el_GR',
229 '/usr/share/locale/el_GR/LC_MESSAGES',
230 '/usr/share/locale/en',
231 '/usr/share/locale/en/LC_MESSAGES',
232 '/usr/share/locale/en@IPA',
233 '/usr/share/locale/en@IPA/LC_MESSAGES',
234 '/usr/share/locale/en@boldquot',
235 '/usr/share/locale/en@boldquot/LC_MESSAGES',
236 '/usr/share/locale/en@quot',
237 '/usr/share/locale/en@quot/LC_MESSAGES',
238 '/usr/share/locale/en_AU',
239 '/usr/share/locale/en_AU/LC_MESSAGES',
240 '/usr/share/locale/en_CA',
241 '/usr/share/locale/en_CA/LC_MESSAGES',
242 '/usr/share/locale/en_GB',
243 '/usr/share/locale/en_GB/LC_MESSAGES',
244 '/usr/share/locale/en_US',
245 '/usr/share/locale/en_US/LC_MESSAGES',
246 '/usr/share/locale/eo',
247 '/usr/share/locale/eo/LC_MESSAGES',
248 '/usr/share/locale/es',
249 '/usr/share/locale/es/LC_MESSAGES',
250 '/usr/share/locale/es_AR',
251 '/usr/share/locale/es_AR/LC_MESSAGES',
252 '/usr/share/locale/es_CL',
253 '/usr/share/locale/es_CL/LC_MESSAGES',
254 '/usr/share/locale/es_CO',
255 '/usr/share/locale/es_CO/LC_MESSAGES',
256 '/usr/share/locale/es_CR',
257 '/usr/share/locale/es_CR/LC_MESSAGES',
258 '/usr/share/locale/es_DO',
259 '/usr/share/locale/es_DO/LC_MESSAGES',
260 '/usr/share/locale/es_EC',
261 '/usr/share/locale/es_EC/LC_MESSAGES',
262 '/usr/share/locale/es_ES',
263 '/usr/share/locale/es_ES/LC_MESSAGES',
264 '/usr/share/locale/es_GT',
265 '/usr/share/locale/es_GT/LC_MESSAGES',
266 '/usr/share/locale/es_HN',
267 '/usr/share/locale/es_HN/LC_MESSAGES',
268 '/usr/share/locale/es_MX',
269 '/usr/share/locale/es_MX/LC_MESSAGES',
270 '/usr/share/locale/es_NI',
271 '/usr/share/locale/es_NI/LC_MESSAGES',
272 '/usr/share/locale/es_PA',
273 '/usr/share/locale/es_PA/LC_MESSAGES',
274 '/usr/share/locale/es_PE',
275 '/usr/share/locale/es_PE/LC_MESSAGES',
276 '/usr/share/locale/es_PR',
277 '/usr/share/locale/es_PR/LC_MESSAGES',
278 '/usr/share/locale/es_SV',
279 '/usr/share/locale/es_SV/LC_MESSAGES',
280 '/usr/share/locale/es_UY',
281 '/usr/share/locale/es_UY/LC_MESSAGES',
282 '/usr/share/locale/es_VE',
283 '/usr/share/locale/es_VE/LC_MESSAGES',
284 '/usr/share/locale/et',
285 '/usr/share/locale/et/LC_MESSAGES',
286 '/usr/share/locale/et_EE',
287 '/usr/share/locale/et_EE/LC_MESSAGES',
288 '/usr/share/locale/eu',
289 '/usr/share/locale/eu/LC_MESSAGES',
290 '/usr/share/locale/eu_ES',
291 '/usr/share/locale/eu_ES/LC_MESSAGES',
292 '/usr/share/locale/fa',
293 '/usr/share/locale/fa/LC_MESSAGES',
294 '/usr/share/locale/fi',
295 '/usr/share/locale/fi/LC_MESSAGES',
296 '/usr/share/locale/fi_FI',
297 '/usr/share/locale/fi_FI/LC_MESSAGES',
298 '/usr/share/locale/fo',
299 '/usr/share/locale/fo/LC_MESSAGES',
300 '/usr/share/locale/fr',
301 '/usr/share/locale/fr/LC_MESSAGES',
302 '/usr/share/locale/fr_CA',
303 '/usr/share/locale/fr_CA/LC_MESSAGES',
304 '/usr/share/locale/fr_CH',
305 '/usr/share/locale/fr_CH/LC_MESSAGES',
306 '/usr/share/locale/fr_FR',
307 '/usr/share/locale/fr_FR/LC_MESSAGES',
308 '/usr/share/locale/fy',
309 '/usr/share/locale/fy/LC_MESSAGES',
310 '/usr/share/locale/ga',
311 '/usr/share/locale/ga/LC_MESSAGES',
312 '/usr/share/locale/gd',
313 '/usr/share/locale/gd/LC_MESSAGES',
314 '/usr/share/locale/gez',
315 '/usr/share/locale/gez/LC_MESSAGES',
316 '/usr/share/locale/gl',
317 '/usr/share/locale/gl/LC_MESSAGES',
318 '/usr/share/locale/gn',
319 '/usr/share/locale/gn/LC_MESSAGES',
320 '/usr/share/locale/gr',
321 '/usr/share/locale/gr/LC_MESSAGES',
322 '/usr/share/locale/gu',
323 '/usr/share/locale/gu/LC_MESSAGES',
324 '/usr/share/locale/gv',
325 '/usr/share/locale/gv/LC_MESSAGES',
326 '/usr/share/locale/haw',
327 '/usr/share/locale/haw/LC_MESSAGES',
328 '/usr/share/locale/he',
329 '/usr/share/locale/he/LC_MESSAGES',
330 '/usr/share/locale/hi',
331 '/usr/share/locale/hi/LC_MESSAGES',
332 '/usr/share/locale/hr',
333 '/usr/share/locale/hr/LC_MESSAGES',
334 '/usr/share/locale/hu',
335 '/usr/share/locale/hu/LC_MESSAGES',
336 '/usr/share/locale/hy',
337 '/usr/share/locale/hy/LC_MESSAGES',
338 '/usr/share/locale/ia',
339 '/usr/share/locale/ia/LC_MESSAGES',
340 '/usr/share/locale/id',
341 '/usr/share/locale/id/LC_MESSAGES',
342 '/usr/share/locale/is',
343 '/usr/share/locale/is/LC_MESSAGES',
344 '/usr/share/locale/it',
345 '/usr/share/locale/it/LC_MESSAGES',
346 '/usr/share/locale/it_CH',
347 '/usr/share/locale/it_CH/LC_MESSAGES',
348 '/usr/share/locale/it_IT',
349 '/usr/share/locale/it_IT/LC_MESSAGES',
350 '/usr/share/locale/iu',
351 '/usr/share/locale/iu/LC_MESSAGES',
352 '/usr/share/locale/ja',
353 '/usr/share/locale/ja/LC_MESSAGES',
354 '/usr/share/locale/ja_JP.EUC',
355 '/usr/share/locale/ja_JP.EUC/LC_MESSAGES',
356 '/usr/share/locale/ja_JP.SJIS',
357 '/usr/share/locale/ja_JP.SJIS/LC_MESSAGES',
358 '/usr/share/locale/ja_JP.eucJP',
359 '/usr/share/locale/ja_JP.eucJP/LC_MESSAGES',
360 '/usr/share/locale/ka',
361 '/usr/share/locale/ka/LC_MESSAGES',
362 '/usr/share/locale/kk',
363 '/usr/share/locale/kk/LC_MESSAGES',
364 '/usr/share/locale/kl',
365 '/usr/share/locale/kl/LC_MESSAGES',
366 '/usr/share/locale/km',
367 '/usr/share/locale/km/LC_MESSAGES',
368 '/usr/share/locale/kn',
369 '/usr/share/locale/kn/LC_MESSAGES',
370 '/usr/share/locale/ko',
371 '/usr/share/locale/ko/LC_MESSAGES',
372 '/usr/share/locale/kok',
373 '/usr/share/locale/kok/LC_MESSAGES',
374 '/usr/share/locale/ku',
375 '/usr/share/locale/ku/LC_MESSAGES',
376 '/usr/share/locale/kw',
377 '/usr/share/locale/kw/LC_MESSAGES',
378 '/usr/share/locale/ky',
379 '/usr/share/locale/ky/LC_MESSAGES',
380 '/usr/share/locale/lg',
381 '/usr/share/locale/lg/LC_MESSAGES',
382 '/usr/share/locale/li',
383 '/usr/share/locale/li/LC_MESSAGES',
384 '/usr/share/locale/lo',
385 '/usr/share/locale/lo/LC_MESSAGES',
386 '/usr/share/locale/lt',
387 '/usr/share/locale/lt/LC_MESSAGES',
388 '/usr/share/locale/lv',
389 '/usr/share/locale/lv/LC_MESSAGES',
390 '/usr/share/locale/mg',
391 '/usr/share/locale/mg/LC_MESSAGES',
392 '/usr/share/locale/mi',
393 '/usr/share/locale/mi/LC_MESSAGES',
394 '/usr/share/locale/mk',
395 '/usr/share/locale/mk/LC_MESSAGES',
396 '/usr/share/locale/ml',
397 '/usr/share/locale/ml/LC_MESSAGES',
398 '/usr/share/locale/mn',
399 '/usr/share/locale/mn/LC_MESSAGES',
400 '/usr/share/locale/mr',
401 '/usr/share/locale/mr/LC_MESSAGES',
402 '/usr/share/locale/ms',
403 '/usr/share/locale/ms/LC_MESSAGES',
404 '/usr/share/locale/mt',
405 '/usr/share/locale/mt/LC_MESSAGES',
406 '/usr/share/locale/my',
407 '/usr/share/locale/my/LC_MESSAGES',
408 '/usr/share/locale/nb',
409 '/usr/share/locale/nb/LC_MESSAGES',
410 '/usr/share/locale/nb_NO',
411 '/usr/share/locale/nb_NO/LC_MESSAGES',
412 '/usr/share/locale/nds',
413 '/usr/share/locale/nds/LC_MESSAGES',
414 '/usr/share/locale/ne',
415 '/usr/share/locale/ne/LC_MESSAGES',
416 '/usr/share/locale/nl',
417 '/usr/share/locale/nl/LC_MESSAGES',
418 '/usr/share/locale/nl_BE',
419 '/usr/share/locale/nl_BE/LC_MESSAGES',
420 '/usr/share/locale/nn',
421 '/usr/share/locale/nn/LC_MESSAGES',
422 '/usr/share/locale/nn_NO',
423 '/usr/share/locale/nn_NO/LC_MESSAGES',
424 '/usr/share/locale/nso',
425 '/usr/share/locale/nso/LC_MESSAGES',
426 '/usr/share/locale/oc',
427 '/usr/share/locale/oc/LC_MESSAGES',
428 '/usr/share/locale/om',
429 '/usr/share/locale/om/LC_MESSAGES',
430 '/usr/share/locale/or',
431 '/usr/share/locale/or/LC_MESSAGES',
432 '/usr/share/locale/pa',
433 '/usr/share/locale/pa/LC_MESSAGES',
434 '/usr/share/locale/pl',
435 '/usr/share/locale/pl/LC_MESSAGES',
436 '/usr/share/locale/pl_PL',
437 '/usr/share/locale/pl_PL/LC_MESSAGES',
438 '/usr/share/locale/ps',
439 '/usr/share/locale/ps/LC_MESSAGES',
440 '/usr/share/locale/pt',
441 '/usr/share/locale/pt/LC_MESSAGES',
442 '/usr/share/locale/pt_BR',
443 '/usr/share/locale/pt_BR/LC_MESSAGES',
444 '/usr/share/locale/pt_PT',
445 '/usr/share/locale/pt_PT/LC_MESSAGES',
446 '/usr/share/locale/rm',
447 '/usr/share/locale/rm/LC_MESSAGES',
448 '/usr/share/locale/ro',
449 '/usr/share/locale/ro/LC_MESSAGES',
450 '/usr/share/locale/ru',
451 '/usr/share/locale/ru/LC_MESSAGES',
452 '/usr/share/locale/ru_RU',
453 '/usr/share/locale/ru_RU/LC_MESSAGES',
454 '/usr/share/locale/ru_UA.koi8u',
455 '/usr/share/locale/ru_UA.koi8u/LC_MESSAGES',
456 '/usr/share/locale/rw',
457 '/usr/share/locale/rw/LC_MESSAGES',
458 '/usr/share/locale/sa',
459 '/usr/share/locale/sa/LC_MESSAGES',
460 '/usr/share/locale/se',
461 '/usr/share/locale/se/LC_MESSAGES',
462 '/usr/share/locale/si',
463 '/usr/share/locale/si/LC_MESSAGES',
464 '/usr/share/locale/sid',
465 '/usr/share/locale/sid/LC_MESSAGES',
466 '/usr/share/locale/sk',
467 '/usr/share/locale/sk/LC_MESSAGES',
468 '/usr/share/locale/sl',
469 '/usr/share/locale/sl/LC_MESSAGES',
470 '/usr/share/locale/sl_SI',
471 '/usr/share/locale/sl_SI/LC_MESSAGES',
472 '/usr/share/locale/so',
473 '/usr/share/locale/so/LC_MESSAGES',
474 '/usr/share/locale/sp',
475 '/usr/share/locale/sp/LC_MESSAGES',
476 '/usr/share/locale/sq',
477 '/usr/share/locale/sq/LC_MESSAGES',
478 '/usr/share/locale/sq_AL',
479 '/usr/share/locale/sq_AL/LC_MESSAGES',
480 '/usr/share/locale/sr',
481 '/usr/share/locale/sr/LC_MESSAGES',
482 '/usr/share/locale/sr@Latn',
483 '/usr/share/locale/sr@Latn/LC_MESSAGES',
484 '/usr/share/locale/sr@ije',
485 '/usr/share/locale/sr@ije/LC_MESSAGES',
486 '/usr/share/locale/ss',
487 '/usr/share/locale/ss/LC_MESSAGES',
488 '/usr/share/locale/st',
489 '/usr/share/locale/st/LC_MESSAGES',
490 '/usr/share/locale/sv',
491 '/usr/share/locale/sv/LC_MESSAGES',
492 '/usr/share/locale/sw',
493 '/usr/share/locale/sw/LC_MESSAGES',
494 '/usr/share/locale/syr',
495 '/usr/share/locale/syr/LC_MESSAGES',
496 '/usr/share/locale/ta',
497 '/usr/share/locale/ta/LC_MESSAGES',
498 '/usr/share/locale/te',
499 '/usr/share/locale/te/LC_MESSAGES',
500 '/usr/share/locale/tg',
501 '/usr/share/locale/tg/LC_MESSAGES',
502 '/usr/share/locale/th',
503 '/usr/share/locale/th/LC_MESSAGES',
504 '/usr/share/locale/ti',
505 '/usr/share/locale/ti/LC_MESSAGES',
506 '/usr/share/locale/tig',
507 '/usr/share/locale/tig/LC_MESSAGES',
508 '/usr/share/locale/tk',
509 '/usr/share/locale/tk/LC_MESSAGES',
510 '/usr/share/locale/tl',
511 '/usr/share/locale/tl/LC_MESSAGES',
512 '/usr/share/locale/tr',
513 '/usr/share/locale/tr/LC_MESSAGES',
514 '/usr/share/locale/tt',
515 '/usr/share/locale/tt/LC_MESSAGES',
516 '/usr/share/locale/ug',
517 '/usr/share/locale/ug/LC_MESSAGES',
518 '/usr/share/locale/uk',
519 '/usr/share/locale/uk/LC_MESSAGES',
520 '/usr/share/locale/uk_UA',
521 '/usr/share/locale/uk_UA/LC_MESSAGES',
522 '/usr/share/locale/ur',
523 '/usr/share/locale/ur/LC_MESSAGES',
524 '/usr/share/locale/urd',
525 '/usr/share/locale/urd/LC_MESSAGES',
526 '/usr/share/locale/uz',
527 '/usr/share/locale/uz/LC_MESSAGES',
528 '/usr/share/locale/uz@cyrillic',
529 '/usr/share/locale/uz@cyrillic/LC_MESSAGES',
530 '/usr/share/locale/ve',
531 '/usr/share/locale/ve/LC_MESSAGES',
532 '/usr/share/locale/ven',
533 '/usr/share/locale/ven/LC_MESSAGES',
534 '/usr/share/locale/vi',
535 '/usr/share/locale/vi/LC_MESSAGES',
536 '/usr/share/locale/wa',
537 '/usr/share/locale/wa/LC_MESSAGES',
538 '/usr/share/locale/wal',
539 '/usr/share/locale/wal/LC_MESSAGES',
540 '/usr/share/locale/wo',
541 '/usr/share/locale/wo/LC_MESSAGES',
542 '/usr/share/locale/xh',
543 '/usr/share/locale/xh/LC_MESSAGES',
544 '/usr/share/locale/yi',
545 '/usr/share/locale/yi/LC_MESSAGES',
546 '/usr/share/locale/yo',
547 '/usr/share/locale/yo/LC_MESSAGES',
548 '/usr/share/locale/zh',
549 '/usr/share/locale/zh/LC_MESSAGES',
550 '/usr/share/locale/zh_CN',
551 '/usr/share/locale/zh_CN.GB2312',
552 '/usr/share/locale/zh_CN.GB2312/LC_MESSAGES',
553 '/usr/share/locale/zh_CN/LC_MESSAGES',
554 '/usr/share/locale/zh_HK',
555 '/usr/share/locale/zh_HK/LC_MESSAGES',
556 '/usr/share/locale/zh_TW',
557 '/usr/share/locale/zh_TW.Big5',
558 '/usr/share/locale/zh_TW.Big5/LC_MESSAGES',
559 '/usr/share/locale/zh_TW/LC_MESSAGES',
560 '/usr/share/locale/zu',
561 '/usr/share/locale/zu/LC_MESSAGES',
563 '/usr/share/man/man1',
564 '/usr/share/man/man2',
565 '/usr/share/man/man3',
566 '/usr/share/man/man4',
567 '/usr/share/man/man5',
568 '/usr/share/man/man6',
569 '/usr/share/man/man7',
570 '/usr/share/man/man8',
571 '/usr/share/man/man9',
572 '/usr/share/man/mann',
574 '/usr/share/mime/packages',
577 '/usr/share/pixmaps',
578 '/usr/share/pkgconfig',
580 '/usr/share/sgml/docbook',
585 '/usr/share/xml/docbook',
586 '/usr/share/xsessions',
594 '/var/adm/backup/rpmdb',
595 '/var/adm/backup/sysconfig',
596 '/var/adm/fillup-templates',
597 '/var/adm/perl-modules',
607 '/var/lib/pam_devperm',
616 '/var/spool/clientmqueue',
621 '/var/spool/uucp/uucp',
623 '/var/tmp/vi.recover',
626 DEFAULT_GAMES_GROUPS = 'Games'
628 DEFAULT_DANGLING_EXCEPTIONS = (['consolehelper$', 'usermode-consoleonly'],
631 # Standard users and groups from LSB Core 4.0.0: 21.2 User & Group Names
632 DEFAULT_STANDARD_USERS = ('root', 'bin', 'daemon', 'adm', 'lp', 'sync',
633 'shutdown', 'halt', 'mail', 'news', 'uucp',
634 'operator', 'man', 'nobody',)
635 DEFAULT_STANDARD_GROUPS = ('root', 'bin', 'daemon', 'adm', 'lp', 'sync',
636 'shutdown', 'halt', 'mail', 'news', 'uucp',
639 tmp_regex = re.compile('^/tmp/|^(/var|/usr)/tmp/')
640 sub_bin_regex = re.compile('^(/usr)?/s?bin/\S+/')
641 backup_regex = re.compile('(~|\#[^/]+\#|\.orig|\.rej)$')
642 compr_regex = re.compile('\.(gz|z|Z|zip|bz2|lzma|xz)$')
643 absolute_regex = re.compile('^/([^/]+)')
644 absolute2_regex = re.compile('^/?([^/]+)')
645 points_regex = re.compile('^\.\./(.*)')
646 doc_regex = re.compile('^/usr(/share|/X11R6)?/(doc|man|info)/|^/opt/kde3/share/doc|^/usr/share/gnome/help')
647 bin_regex = re.compile('^/(?:usr/(?:s?bin|games)|s?bin)/(.*)')
648 includefile_regex = re.compile('\.(c|h)(pp|xx)?$', re.IGNORECASE)
649 develfile_regex = re.compile('\.(a|cmxa?|mli?|gir)$')
650 buildconfigfile_regex = re.compile('(\.pc|/bin/.+-config)$')
651 docdir_examples_regex = re.compile('^/usr/(?:share/doc/packages|lib(?:64))/[^/]+/(?:example|demo|script|contrib)')
652 # room for improvement with catching more -R, but also for false positives...
653 buildconfig_rpath_regex = re.compile('(?:-rpath|Wl,-R)\\b')
654 sofile_regex = re.compile('/lib(64)?/(.+/)?lib[^/]+\.so$')
655 devel_regex = re.compile('(.*)-(debug(info)?|devel|headers|source|static)$')
656 debuginfo_package_regex = re.compile('-debug(info)?$')
657 lib_regex = re.compile('/lib(64)?/lib[^/]*\.so\.[\d\.-]*$')
658 ldconfig_regex = re.compile('^[^#]*ldconfig', re.MULTILINE)
659 depmod_regex = re.compile('^[^#]*depmod', re.MULTILINE)
660 install_info_regex = re.compile('^[^#]*install-info', re.MULTILINE)
661 perl_temp_file_regex = re.compile('.*perl.*/(\.packlist|perllocal\.pod)$')
662 scm_regex=re.compile('/(CVS|RCS)(/[^/]+)?$|/\.(bzr|cvs|git|hg)ignore$|/\.hgtags$|/\.(bzr|git|hg|svn)/|/(\.arch-ids|{arch})/|,v$')
663 games_path_regex = re.compile('^/usr(/lib(64)?)?/games/')
664 games_group_regex = re.compile(Config.getOption('RpmGamesGroups', DEFAULT_GAMES_GROUPS))
665 dangling_exceptions = Config.getOption('DanglingSymlinkExceptions', DEFAULT_DANGLING_EXCEPTIONS)
666 logrotate_regex = re.compile('^/etc/logrotate\.d/(.*)')
667 module_rpms_ok = Config.getOption('KernelModuleRPMsOK', True)
668 kernel_modules_regex = re.compile('^/lib/modules/(2\.[23456]\.[0-9]+[^/]*?)/')
669 kernel_package_regex = re.compile('^kernel(22)?(-)?(smp|enterprise|bigmem|secure|BOOT|i686-up-4GB|p3-smp-64GB)?')
670 normal_zero_length_regex = re.compile('^/etc/security/console\.apps/|/\.nosearch$|/__init__\.py$')
671 perl_regex = re.compile('^/usr/lib/perl5/(?:vendor_perl/)?([0-9]+\.[0-9]+)\.([0-9]+)/')
672 python_regex = re.compile('^/usr/lib(?:64)?/python([.0-9]+)/')
673 python_bytecode_regex_pep3147 = re.compile('^(.*)/__pycache__/(.*)\.(.*)(\.py[oc])$')
674 python_bytecode_regex = re.compile('^(.*)(\.py[oc])$')
675 python_default_version = Config.getOption('PythonDefaultVersion', None)
676 perl_version_trick = Config.getOption('PerlVersionTrick', True)
677 log_regex = re.compile('^/var/log/[^/]+$')
678 lib_path_regex = re.compile('^(/usr(/X11R6)?)?/lib(64)?')
679 lib_package_regex = re.compile('^(lib|.+-libs)')
680 hidden_file_regex = re.compile('/\.[^/]*$')
681 manifest_perl_regex = re.compile('^/usr/share/doc/perl-.*/MANIFEST(\.SKIP)?$')
682 shebang_regex = re.compile('^#!\s*(\S+)')
683 interpreter_regex = re.compile('^/(usr/)?(s?bin|games|libexec(/.+)?|(lib(64)?|share)/.+)/[^/]+$')
684 script_regex = re.compile('^/((usr/)?s?bin|etc/(rc\.d/init\.d|X11/xinit\.d|cron\.(hourly|daily|monthly|weekly)))/')
685 sourced_script_regex = re.compile('^/etc/(bash_completion\.d|profile\.d|/sbin/conf.d)/')
686 use_utf8 = Config.getOption('UseUTF8', Config.USEUTF8_DEFAULT)
687 skipdocs_regex = re.compile(Config.getOption('SkipDocsRegexp', '\.(?:rtf|x?html?|svg|ml[ily]?)$'), re.IGNORECASE)
688 meta_package_regex = re.compile(Config.getOption('MetaPackageRegexp', '^(bundle|task)-'))
689 filesys_packages = ['filesystem'] # TODO: make configurable?
690 quotes_regex = re.compile('[\'"]+')
692 for idx in range(0, len(dangling_exceptions)):
693 dangling_exceptions[idx][0] = re.compile(dangling_exceptions[idx][0])
696 use_relative_symlinks = Config.getOption("UseRelativeSymlinks", True)
698 standard_groups = Config.getOption('StandardGroups', DEFAULT_STANDARD_GROUPS)
699 standard_users = Config.getOption('StandardUsers', DEFAULT_STANDARD_USERS)
701 non_readable_regexs = (re.compile('^/var/log/'),
702 re.compile('^/etc/(g?shadow-?|securetty)$'))
704 man_base_regex = re.compile(r'^/usr(?:/share)?/man/man[^/]+/(.+)\.[1-9n]')
705 man_warn_regex = re.compile(r'^([^:]+:)\d+:\s*')
706 man_nowarn_regex = re.compile(
707 # From Lintian: ignore common undefined macros from pod2man << Perl 5.10
708 r'\`(Tr|IX)\' not defined|'
709 # .so entries won't resolve as we're dealing with stdin
710 r'No such file or directory|'
711 # TODO, better handling for these (see e.g. Lintian)
712 r'(can\'t break|cannot adjust) line')
713 man_warn_category = Config.getOption('ManWarningCategory', 'mac')
715 fsf_license_regex = re.compile('(GNU((\s+(Library|Lesser|Affero))?(\s+General)?\s+Public|\s+Free\s+Documentation)\s+Licen[cs]e|(GP|FD)L)', re.IGNORECASE)
716 fsf_wrong_address_regex = re.compile('(675\s+Mass\s+Ave|59\s+Temple\s+Place|Franklin\s+Steet|02139|02111-1307)', re.IGNORECASE)
718 # loosely inspired from Python Cookbook
719 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/173220
720 text_characters = "".join(map(chr, range(32, 127)) + list("\n\r\t\b"))
721 _null_trans = string.maketrans("", "")
723 def peek(filename, pkg, length=1024):
724 """Peek into a file, return a chunk from its beginning and a flag if it
725 seems to be a text file."""
729 fobj = open(filename, 'rb')
730 chunk = fobj.read(length)
732 except Exception, e: # eg. https://bugzilla.redhat.com/209876
733 printWarning(pkg, 'read-error', e)
736 return (chunk, False)
739 return (chunk, False)
741 if not chunk: # Empty files are considered text
744 # PDF's are binary but often detected as text by the algorithm below
745 if filename.lower().endswith('.pdf') and chunk.startswith('%PDF-'):
746 return (chunk, False)
748 # Get the non-text characters (maps a character to itself then
749 # use the 'remove' option to get rid of the text characters.)
750 t = chunk.translate(_null_trans, text_characters)
752 # If more than 30% non-text characters, then consider it a binary file
753 istext = float(len(t))/len(chunk) <= 0.30
754 return (chunk, istext)
756 # See Python/import.c (in the default and 2.x branches) for a full list of
758 _python_magic_values = {
771 def get_expected_pyc_magic(path):
772 """.pyc/.pyo files embed a 4-byte magic value identifying which version of
773 the python bytecode ABI they are for. Given a path to a .pyc/.pyo file,
774 return a (magic ABI value, python version) tuple. For example,
775 '/usr/lib/python3.1/foo.pyc' should return (3151, '3.1').
776 The first value will be None if the python version was not resolved
777 from the given pathname and the PythonDefaultVersion configuration
778 variable is not set, or if we don't know the magic ABI value for the
779 python version (no matter from which source the version came from).
780 The second value will be None if a python version could not be resolved
781 from the given pathname."""
784 m = python_regex.search(path)
786 ver_from_path = m.group(1)
788 expected_version = ver_from_path or python_default_version
789 expected_magic_value = _python_magic_values.get(expected_version)
791 if not expected_magic_value:
792 return (None, ver_from_path)
794 # In Python 2, if Py_UnicodeFlag is set, Python's import code uses a value
795 # one higher, but this is off by default. In Python 3.0 and 3.1 (but no
796 # longer in 3.2), it always uses the value one higher:
797 if expected_version[:3] in ('3.0', '3.1'):
798 expected_magic_value += 1
800 return (expected_magic_value, ver_from_path)
802 def py_demarshal_long(b):
803 """Counterpart to Python's PyMarshal_ReadLongFromFile, operating on the
804 bytes in a string."""
810 def python_bytecode_to_script(path):
811 """Given a python bytecode path, give the path of the .py file
812 (or None if not python bytecode)."""
814 res = python_bytecode_regex_pep3147.search(path)
816 return res.group(1) + '/' + res.group(2) + '.py'
818 res = python_bytecode_regex.search(path)
820 return res.group(1) + '.py'
824 class FilesCheck(AbstractCheck.AbstractCheck):
827 AbstractCheck.AbstractCheck.__init__(self, 'FilesCheck')
829 def check(self, pkg):
834 for filename in files:
835 if not is_utf8_str(filename):
836 printError(pkg, 'filename-not-utf8', filename)
838 # Rest of the checks are for binary packages only
842 # Check if the package is a development package
843 devel_pkg = devel_regex.search(pkg.name)
845 for p in pkg.provides():
846 if not devel_pkg and devel_regex.search(p[0]):
849 config_files = pkg.configFiles()
850 ghost_files = pkg.ghostFiles()
851 doc_files = pkg.docFiles()
852 req_names = pkg.req_names()
853 lib_package = lib_package_regex.search(pkg.name)
854 is_kernel_package = kernel_package_regex.search(pkg.name)
855 debuginfo_package = debuginfo_package_regex.search(pkg.name)
857 # report these errors only once
858 perl_dep_error = False
859 python_dep_error = False
863 logrotate_file = False
864 debuginfo_srcs = False
865 debuginfo_debugs = False
867 if not lib_package and not doc_files:
868 printWarning(pkg, 'no-documentation')
871 if meta_package_regex.search(pkg.name):
872 printWarning(pkg, 'file-in-meta-package')
873 elif debuginfo_package:
874 printError(pkg, 'empty-debuginfo-package')
876 # Unique (rdev, inode) combinations
879 # All executable files from standard bin dirs (basename => [paths])
880 # Hack: basenames with empty paths links are symlinks (not subject
881 # to duplicate binary check, but yes for man page existence check)
884 # All man page "base" names (without section etc extensions)
885 man_basenames = set()
887 for f, pkgfile in files.items():
890 group = pkgfile.group
891 link = pkgfile.linkto
894 inode = pkgfile.inode
895 is_doc = f in doc_files
898 for match in AbstractCheck.macro_regex.findall(f):
899 printWarning(pkg, 'unexpanded-macro', f, match)
900 if standard_users and user not in standard_users:
901 printWarning(pkg, 'non-standard-uid', f, user)
902 if standard_groups and group not in standard_groups:
903 printWarning(pkg, 'non-standard-gid', f, group)
905 if not module_rpms_ok and kernel_modules_regex.search(f) and not \
907 printError(pkg, "kernel-modules-not-in-kernel-packages", f)
909 if tmp_regex.search(f):
910 printError(pkg, 'dir-or-file-in-tmp', f)
911 elif f.startswith('/mnt/'):
912 printError(pkg, 'dir-or-file-in-mnt', f)
913 elif f.startswith('/opt/'):
914 printError(pkg, 'dir-or-file-in-opt', f)
915 elif f.startswith('/usr/local/'):
916 printError(pkg, 'dir-or-file-in-usr-local', f)
917 elif f.startswith('/var/local/'):
918 printError(pkg, 'dir-or-file-in-var-local', f)
919 elif f.startswith('/var/run/'):
920 if f not in ghost_files:
921 printWarning(pkg, 'non-ghost-in-var-run', f)
922 elif f.startswith('/var/lock/'):
923 if f not in ghost_files:
924 printWarning(pkg, 'non-ghost-in-var-lock', f)
925 elif sub_bin_regex.search(f):
926 printError(pkg, 'subdir-in-bin', f)
927 elif f.startswith('/home/'):
928 printError(pkg, 'dir-or-file-in-home', f)
929 elif '/site_perl/' in f:
930 printWarning(pkg, 'siteperl-in-perl-module', f)
932 if backup_regex.search(f):
933 printError(pkg, 'backup-file-in-package', f)
934 elif scm_regex.search(f):
935 printError(pkg, 'version-control-internal-file', f)
936 elif f.endswith('/.htaccess'):
937 printError(pkg, 'htaccess-file', f)
938 elif hidden_file_regex.search(f) and not f.startswith("/etc/skel/"):
939 printWarning(pkg, 'hidden-file-or-dir', f)
940 elif manifest_perl_regex.search(f):
941 printWarning(pkg, 'manifest-in-perl-module', f)
942 elif f == '/usr/info/dir' or f == '/usr/share/info/dir':
943 printError(pkg, 'info-dir-file', f)
945 res = logrotate_regex.search(f)
947 logrotate_file = True
948 if res.group(1) != pkg.name:
949 printError(pkg, 'incoherent-logrotate-file', f)
951 deps=[x[0] for x in pkg.requires()+pkg.recommends()+pkg.suggests()]
952 if res and not ('logrotate' in deps) and pkg.name != "logrotate":
953 printError(pkg, 'missing-dependency-to-logrotate', "for logrotate script", f)
954 if f.startswith('/etc/cron.') \
955 and not ('cron' in deps) and pkg.name != "cron":
956 printError(pkg, 'missing-dependency-to-cron', "for cron script", f)
957 if f.startswith('/etc/xinet.d/') \
958 and not ('xinetd' in deps) and pkg.name != "xinetd":
959 printError(pkg, 'missing-dependency-to-xinetd', "for xinet.d script", f)
962 ext = compr_regex.search(link)
964 if not re.compile('\.' + ext.group(1) + '$').search(f):
965 printError(pkg, 'compressed-symlink-with-wrong-ext',
970 if log_regex.search(f):
974 hardlink = hardlinks.get((rdev, inode))
975 if hardlink and os.path.dirname(hardlink) != os.path.dirname(f):
976 printWarning(pkg, 'cross-directory-hard-link', f, hardlink)
977 hardlinks[(rdev, inode)] = f
980 if stat.S_ISREG(mode):
982 # set[ug]id bit check
983 if stat.S_ISGID & mode or stat.S_ISUID & mode:
984 if stat.S_ISUID & mode:
985 printError(pkg, 'setuid-binary', f, user, oct(perm))
986 if stat.S_ISGID & mode:
987 if not (group == 'games' and
988 (games_path_regex.search(f) or
989 games_group_regex.search(
990 pkg[rpm.RPMTAG_GROUP]))):
991 printError(pkg, 'setgid-binary', f, group,
993 if mode & 0777 != 0755:
994 printError(pkg, 'non-standard-executable-perm', f,
997 # Prefetch scriptlets, strip quotes from them (#169)
998 postin = pkg[rpm.RPMTAG_POSTIN] or \
999 pkg.scriptprog(rpm.RPMTAG_POSTINPROG)
1001 postin = quotes_regex.sub('', postin)
1002 postun = pkg[rpm.RPMTAG_POSTUN] or \
1003 pkg.scriptprog(rpm.RPMTAG_POSTUNPROG)
1005 postun = quotes_regex.sub('', postun)
1008 if lib_path_regex.search(f):
1013 if log_regex.search(f):
1016 printError(pkg, 'non-root-user-log-file', f, user)
1018 printError(pkg, 'non-root-group-log-file', f, group)
1019 if f not in ghost_files:
1020 printError(pkg, 'non-ghost-file', f)
1024 if os.access(pkgfile.path, os.R_OK):
1025 (chunk, istext) = peek(pkgfile.path, pkg)
1029 res = shebang_regex.search(chunk)
1031 interpreter = res.group(1)
1033 if doc_regex.search(f):
1037 printError(pkg, 'not-listed-as-documentation', f)
1039 # check ldconfig call in %post and %postun
1040 if lib_regex.search(f):
1042 printError(pkg, 'library-without-ldconfig-postin', f)
1044 if not ldconfig_regex.search(postin):
1045 printError(pkg, 'postin-without-ldconfig', f)
1048 printError(pkg, 'library-without-ldconfig-postun', f)
1050 if not ldconfig_regex.search(postun):
1051 printError(pkg, 'postun-without-ldconfig', f)
1053 # check depmod call in %post and %postun
1054 res = not is_kernel_package and kernel_modules_regex.search(f)
1056 kernel_version = res.group(1)
1057 kernel_version_regex = re.compile(
1058 '\\bdepmod\s+-a.*F\s+/boot/System\.map-' +
1059 re.escape(kernel_version) + '\\b.*\\b' +
1060 re.escape(kernel_version) + '\\b',
1061 re.MULTILINE | re.DOTALL)
1063 if not postin or not depmod_regex.search(postin):
1064 printError(pkg, 'module-without-depmod-postin', f)
1065 # check that we run depmod on the right kernel
1066 elif not kernel_version_regex.search(postin):
1067 printError(pkg, 'postin-with-wrong-depmod', f)
1069 if not postun or not depmod_regex.search(postun):
1070 printError(pkg, 'module-without-depmod-postun', f)
1071 # check that we run depmod on the right kernel
1072 elif not kernel_version_regex.search(postun):
1073 printError(pkg, 'postun-with-wrong-depmod', f)
1075 # check install-info call in %post and %postun
1076 if f.startswith('/usr/share/info/'):
1079 'info-files-without-install-info-postin', f)
1080 elif not install_info_regex.search(postin):
1081 printError(pkg, 'postin-without-install-info', f)
1083 preun = pkg[rpm.RPMTAG_PREUN] or \
1084 pkg.scriptprog(rpm.RPMTAG_PREUNPROG)
1085 if not postun and not preun:
1087 'info-files-without-install-info-postun', f)
1089 not install_info_regex.search(postun)) and \
1090 (not preun or not install_info_regex.search(preun)):
1091 printError(pkg, 'postin-without-install-info', f)
1093 # check perl temp file
1094 if perl_temp_file_regex.search(f):
1095 printWarning(pkg, 'perl-temp-file', f)
1097 is_buildconfig = buildconfigfile_regex.search(f) and True
1099 # check rpaths in buildconfig files
1101 ln = pkg.grep(buildconfig_rpath_regex, f)
1103 printError(pkg, 'rpath-in-buildconfig', f, 'lines', ln)
1105 res = bin_regex.search(f)
1107 if mode & 0111 == 0:
1108 printWarning(pkg, 'non-executable-in-bin', f, oct(perm))
1112 bindir_exes.setdefault(exe, []).append(f)
1114 if not devel_pkg and not is_doc and \
1115 (includefile_regex.search(f) or \
1116 develfile_regex.search(f) or is_buildconfig):
1117 printWarning(pkg, 'devel-file-in-non-devel-package', f)
1118 if mode & 0444 != 0444 and perm & 07000 == 0:
1119 ok_nonreadable = False
1120 for regex in non_readable_regexs:
1122 ok_nonreadable = True
1124 if not ok_nonreadable:
1125 printError(pkg, 'non-readable', f, oct(perm))
1126 if size == 0 and not normal_zero_length_regex.search(f) and \
1127 f not in ghost_files:
1128 printError(pkg, 'zero-length', f)
1130 if mode & 0002 != 0:
1131 printError(pkg, 'world-writable', f, oct(perm))
1133 if not perl_dep_error:
1134 res = perl_regex.search(f)
1136 if perl_version_trick:
1137 vers = res.group(1) + '.' + res.group(2)
1139 vers = res.group(1) + res.group(2)
1140 if not (pkg.check_versioned_dep('perl-base', vers) or
1141 pkg.check_versioned_dep('perl', vers)):
1142 printError(pkg, 'no-dependency-on',
1144 perl_dep_error = True
1146 if not python_dep_error:
1147 res = python_regex.search(f)
1148 if res and not (pkg.check_versioned_dep('python-base',
1150 pkg.check_versioned_dep('python',
1152 pkg.check_versioned_dep('python(abi)',
1155 printError(pkg, 'no-dependency-on', 'python(abi)',
1157 python_dep_error = True
1159 source_file = python_bytecode_to_script(f)
1161 if source_file in files:
1163 # Verify that the magic ABI value embedded in the
1164 # .pyc header is correct
1165 found_magic = py_demarshal_long(chunk[:4]) & 0xffff
1166 exp_magic, exp_version = get_expected_pyc_magic(f)
1167 if exp_magic and found_magic != exp_magic:
1168 found_version = 'unknown'
1169 for (pv, pm) in _python_magic_values.items():
1170 if pm == found_magic:
1173 # If expected version was from the file path,
1174 # issue # an error, otherwise a warning.
1175 msg = (pkg, 'python-bytecode-wrong-magic-value',
1176 f, "expected %d (%s), found %d (%s)" %
1178 exp_version or python_default_version,
1179 found_magic, found_version))
1180 if exp_version is not None:
1185 # Verify that the timestamp embedded in the .pyc
1186 # header matches the mtime of the .py file:
1187 pyc_timestamp = py_demarshal_long(chunk[4:8])
1188 # If it's a symlink, check target file mtime.
1189 srcfile = pkg.readlink(files[source_file])
1192 pkg, 'python-bytecode-without-source', f)
1193 elif pyc_timestamp != srcfile.mtime:
1194 cts = datetime.fromtimestamp(
1195 pyc_timestamp).isoformat()
1196 sts = datetime.fromtimestamp(
1197 srcfile.mtime).isoformat()
1199 'python-bytecode-inconsistent-mtime',
1200 f, cts, srcfile.name, sts)
1202 printWarning(pkg, 'python-bytecode-without-source', f)
1204 # normal executable check
1205 if mode & stat.S_IXUSR and perm != 0755:
1206 printError(pkg, 'non-standard-executable-perm',
1208 if mode & 0111 != 0:
1209 if f in config_files:
1210 printError(pkg, 'executable-marked-as-config-file', f)
1211 if not nonexec_file:
1212 # doc_regex and log_regex checked earlier, no match,
1213 # check rest of usual cases here. Sourced scripts have
1214 # their own check, so disregard them here.
1215 nonexec_file = f.endswith('.pc') or \
1216 compr_regex.search(f) or \
1217 includefile_regex.search(f) or \
1218 develfile_regex.search(f) or \
1219 logrotate_regex.search(f)
1220 if nonexec_file and not docdir_examples_regex.search(f):
1221 printWarning(pkg, 'spurious-executable-perm', f)
1222 elif f.startswith('/etc/') and f not in config_files and \
1223 f not in ghost_files and not f.endswith(".desktop"):
1224 printWarning(pkg, 'non-conffile-in-etc', f)
1226 if pkg.arch == 'noarch' and f.startswith('/usr/lib64/python'):
1227 printError(pkg, 'noarch-python-in-64bit-path', f)
1229 if debuginfo_package:
1230 if f.endswith('.debug'):
1231 debuginfo_debugs = True
1233 debuginfo_srcs = True
1235 res = man_base_regex.search(f)
1237 man_basenames.add(res.group(1))
1238 if use_utf8 and chunk:
1239 # TODO: better shell escaping or seq based invocation
1240 cmd = commands.getstatusoutput(
1241 'env LC_ALL=C %s "%s" | gtbl | '
1242 'env LC_ALL=en_US.UTF-8 groff -mtty-char -Tutf8 '
1243 '-P-c -mandoc -w%s >/dev/null' %
1244 (catcmd(f), pkgfile.path, man_warn_category))
1245 for line in cmd[1].split("\n"):
1246 res = man_warn_regex.search(line)
1247 if not res or man_nowarn_regex.search(line):
1249 printWarning(pkg, "manual-page-warning", f,
1254 # ignore perl module shebang -- TODO: disputed...
1255 if f.endswith('.pm'):
1257 # sourced scripts should not be executable
1258 if sourced_script_regex.search(f):
1261 'sourced-script-with-shebang', f,
1263 if mode & 0111 != 0:
1264 printError(pkg, 'executable-sourced-script',
1266 # ...but executed ones should
1267 elif interpreter or mode & 0111 != 0 or \
1268 script_regex.search(f):
1270 if mode & 0111 != 0 and not interpreter_regex.search(interpreter):
1271 printError(pkg, 'wrong-script-interpreter',
1273 elif not nonexec_file and not \
1274 (lib_path_regex.search(f) and
1276 printError(pkg, 'script-without-shebang', f)
1278 if mode & 0111 == 0 and not is_doc and \
1279 interpreter and interpreter.startswith("/"):
1280 printError(pkg, 'non-executable-script', f,
1281 oct(perm), interpreter)
1284 pkg, 'wrong-script-end-of-line-encoding', f)
1285 elif is_doc and not skipdocs_regex.search(f):
1288 pkg, 'wrong-file-end-of-line-encoding', f)
1289 # We check only doc text files for UTF-8-ness;
1290 # checking everything may be slow and can generate
1291 # lots of unwanted noise.
1292 if use_utf8 and not is_utf8(pkgfile.path):
1293 printWarning(pkg, 'file-not-utf8', f)
1294 if fsf_license_regex.search(chunk) and \
1295 fsf_wrong_address_regex.search(chunk):
1296 printError(pkg, 'incorrect-fsf-address', f)
1298 elif is_doc and chunk and compr_regex.search(f):
1299 ff = compr_regex.sub('', f)
1300 if not skipdocs_regex.search(ff):
1301 # compressed docs, eg. info and man files etc
1302 if use_utf8 and not is_utf8(pkgfile.path):
1303 printWarning(pkg, 'file-not-utf8', f)
1306 elif stat.S_ISDIR(mode):
1307 if mode & 01002 == 2: # world writable without sticky bit
1308 printError(pkg, 'world-writable', f, oct(perm))
1310 printError(pkg, 'non-standard-dir-perm', f, oct(perm))
1311 if pkg.name not in filesys_packages and f in STANDARD_DIRS:
1312 printError(pkg, 'standard-dir-owned-by-package', f)
1313 if hidden_file_regex.search(f):
1314 printWarning(pkg, 'hidden-file-or-dir', f)
1317 # symbolic link check
1318 elif stat.S_ISLNK(mode):
1320 is_so = sofile_regex.search(f)
1321 if not devel_pkg and is_so and not link.endswith('.so'):
1322 printWarning(pkg, 'devel-file-in-non-devel-package', f)
1324 res = man_base_regex.search(f)
1326 man_basenames.add(res.group(1))
1328 res = bin_regex.search(f)
1332 bindir_exes.setdefault(exe, [])
1335 r = absolute_regex.search(link)
1337 if not is_so and link not in files and \
1338 link not in req_names:
1339 is_exception = False
1340 for e in dangling_exceptions:
1341 if e[0].search(link):
1345 if is_exception not in req_names:
1346 printWarning(pkg, 'no-dependency-on',
1349 printWarning(pkg, 'dangling-symlink', f, link)
1350 linktop = r.group(1)
1351 r = absolute_regex.search(f)
1353 filetop = r.group(1)
1354 if filetop == linktop or use_relative_symlinks:
1355 printWarning(pkg, 'symlink-should-be-relative',
1360 abslink = '%s/%s' % (os.path.dirname(f), link)
1361 abslink = os.path.normpath(abslink)
1362 if abslink not in files and abslink not in req_names:
1363 is_exception = False
1364 for e in dangling_exceptions:
1365 if e[0].search(link):
1369 if is_exception not in req_names:
1370 printWarning(pkg, 'no-dependency-on',
1373 printWarning(pkg, 'dangling-relative-symlink',
1375 pathcomponents = f.split('/')[1:]
1376 r = points_regex.search(link)
1382 if len(pathcomponents) == 0:
1383 printError(pkg, 'symlink-has-too-many-up-segments',
1387 lastpop = pathcomponents[0]
1388 pathcomponents = pathcomponents[1:]
1389 r = points_regex.search(mylink)
1391 if mylink and lastpop:
1392 r = absolute2_regex.search(mylink)
1393 linktop = r.group(1)
1395 # does the link go up and then down into the same
1397 #if linktop == lastpop:
1398 # printWarning(pkg, 'lengthy-symlink', f, link)
1400 # have we reached the root directory?
1401 if len(pathcomponents) == 0 and linktop != lastpop \
1402 and not use_relative_symlinks:
1403 # relative link into other toplevel directory
1404 printWarning(pkg, 'symlink-should-be-absolute', f,
1406 # check additional segments for mistakes like
1408 for linksegment in mylink.split('/'):
1409 if linksegment == '..':
1412 'symlink-contains-up-and-down-segments',
1415 if f.startswith('/etc/cron.d/'):
1416 if stat.S_ISLNK(mode):
1417 printError(pkg, 'symlink-crontab-file', f)
1420 printError(pkg, 'executable-crontab-file', f)
1422 if stat.S_IWGRP & mode or stat.S_IWOTH & mode:
1423 printError(pkg, 'non-owner-writeable-only-crontab-file', f)
1425 if log_file and not logrotate_file:
1426 printWarning(pkg, 'log-files-without-logrotate', log_file)
1428 if lib_package and lib_file and non_lib_file:
1429 printError(pkg, 'outside-libdir-files', non_lib_file)
1431 if debuginfo_package and debuginfo_debugs and not debuginfo_srcs:
1432 printError(pkg, 'debuginfo-without-sources')
1434 for exe, paths in bindir_exes.items():
1436 printWarning(pkg, "duplicate-executable", exe, paths)
1437 if exe not in man_basenames:
1438 printWarning(pkg, "no-manual-page-for-binary", exe)
1440 # Create an object to enable the auto registration of the test
1441 check = FilesCheck()
1445 '''The package contains no documentation (README, doc, etc).
1446 You have to include documentation files.''',
1448 'not-listed-as-documentation',
1449 '''The documentation files of this package are not listed with
1450 the standard %doc tag.''',
1453 '''A file in this package is owned by a non standard user.
1455 %s.''' % ", ".join(standard_users),
1458 '''A file in this package is owned by a non standard group.
1459 Standard groups are:
1460 %s.''' % ", ".join(standard_groups),
1462 'library-without-ldconfig-postin',
1463 '''This package contains a library and provides no %post scriptlet containing
1464 a call to ldconfig.''',
1466 'postin-without-ldconfig',
1467 '''This package contains a library and its %post scriptlet doesn't call
1470 'library-without-ldconfig-postun',
1471 '''This package contains a library and provides no %postun scriptlet containing
1472 a call to ldconfig.''',
1474 'postun-without-ldconfig',
1475 '''This package contains a library and its %postun doesn't call ldconfig.''',
1477 'info-files-without-install-info-postin',
1478 '''This package contains info files and provides no %post scriptlet containing
1479 a call to install-info.''',
1481 'postin-without-install-info',
1482 '''This package contains info files and its %post doesn't call install-info.''',
1484 'info-files-without-install-info-postun',
1485 '''This package contains info files and provides no %postun scriptlet containing
1486 a call to install-info.''',
1488 'postun-without-install-info',
1489 '''This package contains info files and its %postun doesn't call
1493 '''You have a perl temporary file in your package. Usually, this
1494 file is beginning with a dot (.) and contain "perl" in its name.''',
1496 'dir-or-file-in-tmp',
1497 '''A file in the package is located in /tmp. It's not permitted
1498 for packages to install files in this directory.''',
1500 'dir-or-file-in-mnt',
1501 '''A file in the package is located in /mnt. It's not permitted
1502 for packages to install files in this directory.''',
1504 'dir-or-file-in-opt',
1505 '''A file in the package is located in /opt. It's not permitted
1506 for packages to install files in this directory.''',
1508 'dir-or-file-in-usr-local',
1509 '''A file in the package is located in /usr/local. It's not permitted
1510 for packages to install files in this directory.''',
1512 'dir-or-file-in-var-local',
1513 '''A file in the package is located in /var/local. It's not permitted
1514 for packages to install files in this directory.''',
1516 'non-ghost-in-var-run',
1517 '''A file or directory in the package is located in /var/run. Files installed
1518 in this directory should be marked as %ghost and created at runtime to work
1519 properly in tmpfs /var/run setups.''',
1521 'non-ghost-in-var-lock',
1522 '''A file or directory in the package is located in /var/lock. Files installed
1523 in this directory should be marked as %ghost and created at runtime to work
1524 properly in tmpfs /var/lock setups.''',
1527 '''The package contains a subdirectory in /usr/bin. It's not permitted to
1528 create a subdir there. Create it in /usr/lib/ instead.''',
1530 'backup-file-in-package',
1531 '''You have a file whose name looks like one for backup files, usually created
1532 by an editor or resulting from applying unclean (fuzzy, or ones with line
1533 offsets) patches.''',
1535 'dir-or-file-in-home',
1536 '''A file in the package is located in /home. It's not permitted
1537 for packages to install files in this directory.''',
1539 'version-control-internal-file',
1540 '''You have included file(s) internally used by a version control system
1541 in the package. Move these files out of the package and rebuild it.''',
1544 '''You have individual apache configuration .htaccess file(s) in your package.
1545 Replace them by a central configuration file in /etc/, according to the web
1546 application packaging policy for your distribution.''',
1549 '''You have /usr/info/dir or /usr/share/info/dir in your package. It will cause
1550 conflicts with other packages and thus is not allowed. Please remove it and
1551 rebuild your package.''',
1553 'non-conffile-in-etc',
1554 '''A non-executable file in your package is being installed in /etc, but is not
1555 a configuration file. All non-executable files in /etc should be configuration
1556 files. Mark the file as %config in the spec file.''',
1558 'compressed-symlink-with-wrong-ext',
1559 '''The symlink points to a compressed file but doesn't use the same
1563 '''The file is setuid; this may be dangerous, especially if this
1564 file is setuid root. Sometimes file capabilities can be used instead of
1568 '''The file is setgid. Usually this is a packaging bug. If this is a game,
1569 then, you should use the proper rpm group, or location.''',
1571 'non-standard-executable-perm',
1572 '''A standard executable should have permission set to 0755. If you get this
1573 message, it means that you have a wrong executable permissions in some files
1574 included in your package.''',
1576 'non-executable-in-bin',
1577 '''A file is being installed in /usr/bin, but is not an executable. Be sure
1578 that the file is an executable or that it has executable permissions.''',
1580 'devel-file-in-non-devel-package',
1581 '''A development file (usually source code) is located in a non-devel
1582 package. If you want to include source code in your package, be sure to
1583 create a development package.''',
1585 'non-standard-dir-perm',
1586 '''A standard directory should have permission set to 0755. If you get this
1587 message, it means that you have wrong directory permissions in some dirs
1588 included in your package.''',
1590 'spurious-executable-perm',
1591 '''The file is installed with executable permissions, but was identified as one
1592 that probably should not be executable. Verify if the executable bits are
1593 desired, and remove if not.
1594 NOTE: example scripts should be packaged under %docdir/examples, which will avoid
1599 '''A file or directory in the package is installed with world writable
1600 permissions, which is most likely a security issue.''',
1602 'standard-dir-owned-by-package',
1603 '''This package owns a directory that is part of the standard hierarchy, which
1604 can lead to default directory permissions or ownerships being changed to
1605 something non-standard.''',
1611 'cross-directory-hard-link',
1612 '''File is hard linked across directories. This can cause problems in
1613 installations where the directories are located on different devices.''',
1616 '''The target of the symbolic link does not exist within this package or its
1617 file based dependencies. Verify spelling of the link target and that the
1618 target is included in a package in this package's dependency chain.''',
1620 'symlink-should-be-relative',
1621 '''Absolute symlinks are problematic eg. when working with chroot environments.
1622 symlinks(8) is a tool that can be useful for creating/dealing with relative
1623 symlinks at package build time.''',
1625 'dangling-relative-symlink',
1626 '''The target of the symbolic link does not exist within this package or its
1627 file based dependencies. Verify spelling of the link target and that the
1628 target is included in a package in this package's dependency chain.''',
1630 'symlink-has-too-many-up-segments',
1634 'symlink-should-be-absolute',
1638 'symlink-contains-up-and-down-segments',
1643 '''The file can't be read by everybody. If this is expected (for security
1644 reasons), contact your rpmlint distributor to get it added to the list of
1645 exceptions for your distro (or add it to your local configuration if you
1646 installed rpmlint from the source tarball).''',
1648 'incoherent-logrotate-file',
1649 '''Your logrotate file should be named /etc/logrotate.d/<package name>.''',
1651 'non-root-user-log-file',
1652 '''If you need log files owned by a non-root user, just create a subdir in
1653 /var/log and put your log files in it.''',
1655 'non-root-group-log-file',
1656 '''If you need log files owned by a non-root group, just create a subdir in
1657 /var/log and put your log files in it.''',
1660 '''File should be tagged %ghost.''',
1662 'outside-libdir-files',
1663 '''This library package must not contain non library files to allow 64
1664 and 32 bits versions of the package to coexist.''',
1666 'hidden-file-or-dir',
1667 '''The file or directory is hidden. You should see if this is normal,
1668 and delete it from the package if not.''',
1670 'module-without-depmod-postin',
1671 '''This package contains a kernel module but provides no call to depmod in the
1672 %post scriptlet.''',
1674 'postin-with-wrong-depmod',
1675 '''This package contains a kernel module but its %post scriptlet calls depmod
1676 for the wrong kernel.''',
1678 'module-without-depmod-postun',
1679 '''This package contains a kernel module but provides no call to depmod in the
1680 %postun scriptlet.''',
1682 'postun-with-wrong-depmod',
1683 '''This package contains a kernel module but its %postun scriptlet calls depmod
1684 for the wrong kernel.''',
1686 'log-files-without-logrotate',
1687 '''This package contains files in /var/log/ without adding logrotate
1688 configuration for them.''',
1691 '''This package contains a file whose path contains something that looks like
1692 an unexpanded macro; this is often the sign of a misspelling. Please check your
1695 'manifest-in-perl-module',
1696 '''This perl module package contains a MANIFEST or a MANIFEST.SKIP file
1697 in the documentation directory.''',
1699 'siteperl-in-perl-module',
1700 '''This perl module package installs files under the subdirectory site_perl,
1701 while they must appear under vendor_perl.''',
1703 'executable-marked-as-config-file',
1704 '''Executables must not be marked as config files because that may
1705 prevent upgrades from working correctly. If you need to be able to
1706 customize an executable, make it for example read a config file in
1709 'sourced-script-with-shebang',
1710 '''This text file contains a shebang, but is meant to be sourced, not
1713 'executable-sourced-script',
1714 '''This text file has executable bit set, but is meant to be sourced, not
1717 'wrong-script-interpreter',
1718 '''This script uses an incorrect interpreter. Correct interpreters should
1719 be an absolute path to a file in in /(s)bin or /usr/(s)bin.
1720 Alternatively, if the file isn't supposed to be executed, then don't
1721 mark it as executable. ''',
1723 'non-executable-script',
1724 '''This text file contains a shebang or is located in a path dedicated for
1725 executables, but lacks the executable bits and cannot thus be executed. If
1726 the file is meant to be an executable script, add the executable bits,
1727 otherwise remove the shebang or move the file elsewhere.''',
1729 'script-without-shebang',
1730 '''This text file has executable bits set or is located in a path dedicated
1731 for executables, but lacks a shebang and cannot thus be executed. If the file
1732 is meant to be an executable script, add the shebang, otherwise remove the
1733 executable bits or move the file elsewhere.''',
1735 'wrong-script-end-of-line-encoding',
1736 '''This script has wrong end-of-line encoding, usually caused by creation or
1737 modification on a non-Unix system. It will prevent its execution.''',
1739 'wrong-file-end-of-line-encoding',
1740 '''This file has wrong end-of-line encoding, usually caused by creation or
1741 modification on a non-Unix system. It could prevent it from being displayed
1742 correctly in some circumstances.''',
1745 '''The character encoding of this file is not UTF-8. Consider converting it
1746 in the specfile's %prep section for example using iconv(1).''',
1748 'filename-not-utf8',
1749 '''The character encoding of the name of this file is not UTF-8.
1752 'file-in-meta-package',
1753 '''This package seems to be a meta-package (an empty package used to require
1754 other packages), but it is not empty. You should remove or rename it, see the
1755 option MetaPackageRegexp.''',
1757 'empty-debuginfo-package',
1758 '''This debuginfo package contains no files. This is often a sign of binaries
1759 being unexpectedly stripped too early during the build, rpmbuild not being able
1760 to strip the binaries, the package actually being a noarch one but erratically
1761 packaged as arch dependent, or something else. Verify what the case is, and
1762 if there's no way to produce useful debuginfo out of it, disable creation of
1763 the debuginfo package.''',
1765 'debuginfo-without-sources',
1766 '''This debuginfo package appears to contain debug symbols but no source files.
1767 This is often a sign of binaries being unexpectedly stripped too early during
1768 the build, or being compiled without compiler debug flags (which again often
1769 is a sign of distro's default compiler flags ignored which might have security
1770 consequences), or other compiler flags which result in rpmbuild's debuginfo
1771 extraction not working as expected. Verify that the binaries are not
1772 unexpectedly stripped and that the intended compiler flags are used.''',
1774 'missing-dependency-to-cron',
1775 '''This package installs a file in /etc/cron.*/ but
1776 doesn't require cron to be installed. as cron is not part of the essential packages,
1777 your package should explicitely require cron to make sure that your cron job is
1778 executed. If it is an optional feature of your package, recommend or suggest cron.''',
1780 'missing-dependency-to-logrotate',
1781 '''This package installs a file in /etc/logrotate.d/ but
1782 doesn't require logrotate to be installed. Because logrotate is not part of the essential packages,
1783 your package should explicitely depend on logrotate to make sure that your logrotate
1784 job is executed. If it is an optional feature of your package, recommend or suggest logrotate.''',
1786 'missing-dependency-to-xinetd',
1787 '''This package installs a file in /etc/xinetd.d/ but
1788 doesn't require xinetd to be installed. Because xinetd is not part of the essential packages,
1789 your package should explicitely depend on logrotate to make sure that your xinetd
1790 job is executed. If it is an optional feature of your package, recommend or suggest xinetd.''',
1793 '''This file could not be read. A reason for this could be that the info about
1794 it in the rpm header indicates that it is supposed to be a readable normal file
1795 but it actually is not in the filesystem. Because of this, some checks will
1798 'executable-crontab-file',
1799 '''This crontab file has executable bit set, which is refused by newer version
1802 'non-owner-writeable-only-crontab-file',
1803 '''This crontab file is writeable by other users as its owner, which is refused
1804 by newer version of cron and insecure''',
1806 'symlink-crontab-file',
1807 '''This crontab file is a symbolic link, which is insecure and refused by newer
1810 'rpath-in-buildconfig',
1811 '''This build configuration file contains rpaths which will be introduced into
1812 dependent packages.''',
1814 'python-bytecode-wrong-magic-value',
1815 '''The "magic" ABI version embedded in this python bytecode file isn't equal
1816 to that of the corresponding runtime, which will force the interpreter to
1817 recompile the .py source every time, ignoring the saved bytecode.''',
1819 'python-bytecode-inconsistent-mtime',
1820 '''The timestamp embedded in this python bytecode file isn't equal to the mtime
1821 of the original source file, which will force the interpreter to recompile the
1822 .py source every time, ignoring the saved bytecode.''',
1824 'python-bytecode-without-source',
1825 '''This python bytecode file (.pyo/.pyc) is not accompanied by its original
1826 source file (.py)''',
1828 'duplicate-executable',
1829 '''This executable file exists in more than one standard binary directories.
1830 It can cause problems when dirs in $PATH are reordered.''',
1832 'no-manual-page-for-binary',
1833 '''Each executable in standard binary directories should have a man page.''',
1835 'manual-page-warning',
1836 '''This man page may contain problems that can cause it not to be formatted
1839 'incorrect-fsf-address',
1840 '''The Free Software Foundation address in this file seems to be outdated or
1841 misspelled. Ask upstream to update the address, or if this is a license file,
1842 possibly the entire file with a new copy available from the FSF.''',
1845 # FilesCheck.py ends here
1848 # indent-tabs-mode: nil
1849 # py-indent-offset: 4