3 #include <sys/sysmacros.h>
15 #include <selinux/fs_secure.h>
16 #include <linux/flask/security.h>
17 #include <selinux/flask_util.h> /* for is_flask_enabled() */
18 #define SECURITY_ID_T security_id_t
20 #define SECURITY_ID_T int
25 void print_human_type(unsigned short mode)
27 switch (mode & S_IFMT)
33 printf ("Character Device");
36 printf ("Block Device");
39 printf ("Regular File");
42 printf ("Symbolic Link");
55 void print_human_fstype(struct statfs *statfsbuf)
59 switch (statfsbuf->f_type)
60 #if defined (__linux__)
63 type = strdup("affs");
68 case S_MAGIC_EXT2_OLD:
69 type = strdup("ext2");
72 type = strdup("ext2/ext3");
75 type = strdup("hpfs");
78 type = strdup("isofs");
80 case S_MAGIC_ISOFS_WIN:
81 type = strdup("isofs");
83 case S_MAGIC_ISOFS_R_WIN:
84 type = strdup("isofs");
87 type = strdup("minix");
88 case S_MAGIC_MINIX_30:
89 type = strdup("minix (30 char.)");
91 case S_MAGIC_MINIX_V2:
92 type = strdup("minix v2");
94 case S_MAGIC_MINIX_V2_30:
95 type = strdup("minix v2 (30 char.)");
98 type = strdup("msdos");
101 type = strdup("fat");
104 type = strdup("novell");
107 type = strdup("nfs");
110 type = strdup("proc");
113 type = strdup("smb");
116 type = strdup("xenix");
119 type = strdup("sysv4");
122 type = strdup("sysv2");
125 type = strdup("coh");
128 type = strdup("ufs");
131 type = strdup("xia");
134 type = strdup("ntfs");
137 type = strdup("tmpfs");
139 case S_MAGIC_REISERFS:
140 type = strdup("reiserfs");
143 type = strdup("cramfs");
146 type = strdup("romfs");
149 type = strdup("lustre");
153 type = strdup("ufs");
156 type = strdup("nfs");
159 type = strdup("gfs");
162 type = strdup("lfs");
165 type = strdup("sysv");
168 type = strdup("ftp");
171 type = strdup("tar");
177 type = strdup("cpio");
180 type = strdup("msloss");
183 type = strdup("cpm");
186 type = strdup("hfs");
189 type = strdup("dtfs");
192 type = strdup("grfs");
195 type = strdup("term");
198 type = strdup("dev");
201 type = strdup("proc");
204 type = strdup("ifsock");
207 type = strdup("afs");
210 type = strdup("dfs");
213 type = strdup("proc9");
216 type = strdup("socket");
219 type = strdup("misc");
222 type = strdup("ext2/ext3");
225 type = strdup("http");
228 type = strdup("memfs");
231 type = strdup("iso9660");
235 if ((type = (char*)malloc(30 * sizeof(char))) == NULL) {
236 perror("malloc error");
239 sprintf (type, "UNKNOWN (0x%x)\n", (int)statfsbuf->f_type);
246 void print_human_access(struct stat *statbuf)
251 access[9] = (statbuf->st_mode & S_IXOTH) ?
252 ((statbuf->st_mode & S_ISVTX) ? 't' : 'x') :
253 ((statbuf->st_mode & S_ISVTX) ? 'T' : '-');
254 access[8] = (statbuf->st_mode & S_IWOTH) ? 'w' : '-';
255 access[7] = (statbuf->st_mode & S_IROTH) ? 'r' : '-';
256 access[6] = (statbuf->st_mode & S_IXGRP) ?
257 ((statbuf->st_mode & S_ISGID) ? 's' : 'x') :
258 ((statbuf->st_mode & S_ISGID) ? 'S' : '-');
259 access[5] = (statbuf->st_mode & S_IWGRP) ? 'w' : '-';
260 access[4] = (statbuf->st_mode & S_IRGRP) ? 'r' : '-';
261 access[3] = (statbuf->st_mode & S_IXUSR) ?
262 ((statbuf->st_mode & S_ISUID) ? 's' : 'x') :
263 ((statbuf->st_mode & S_ISUID) ? 'S' : '-');
264 access[2] = (statbuf->st_mode & S_IWUSR) ? 'w' : '-';
265 access[1] = (statbuf->st_mode & S_IRUSR) ? 'r' : '-';
267 switch (statbuf->st_mode & S_IFMT)
296 /* trick gcc into being unable to recognize the %c format so it doesn't
297 * issue its inane warning about %c and two-digit year representations. */
298 static size_t strftime_wrapper(char *s, size_t max, const char *fmt,
300 return strftime(s, max, fmt, tm);
303 void print_human_time(time_t *t)
307 if (strftime_wrapper(str, 40, "%c", localtime(t)) > 0)
310 printf("Cannot calculate human readable time, sorry");
313 /* print statfs info */
314 void print_statfs(char *pformat, char m, char *filename, void *data, SECURITY_ID_T sid)
316 struct statfs *statfsbuf = (struct statfs*)data;
320 unsigned int sbuflen = sizeof(sbuf);
325 strcat(pformat, "s");
326 printf(pformat, filename);
328 #if !defined(__linux__) && defined (__GNU__)
330 strcat(pformat, "Lx");
331 printf(pformat, statfsbuf->f_fsid);
335 strcat(pformat, "x %-8x");
336 printf(pformat, statfsbuf->f_fsid.__val[0], statfsbuf->f_fsid.__val[1]);
341 #ifdef __USE_FILE_OFFSET64
342 strcat(pformat, "lu");
344 strcat(pformat, "d");
346 printf(pformat, statfsbuf->f_namelen);
349 #ifdef __USE_FILE_OFFSET64
350 strcat(pformat, "lx");
352 strcat(pformat, "x");
354 printf(pformat, statfsbuf->f_type);
357 /* print_human_fstype(statfsbuf, pformat);*/
358 print_human_fstype(statfsbuf);
361 #ifdef __USE_FILE_OFFSET64
362 strcat(pformat, "lld");
364 #if !defined(__linux__) && defined (__GNU__)
365 strcat(pformat, "d");
367 strcat(pformat, "ld");
370 printf(pformat, statfsbuf->f_blocks);
373 #ifdef __USE_FILE_OFFSET64
374 strcat(pformat, "lld");
376 #if !defined(__linux__) && defined (__GNU__)
377 strcat(pformat, "d");
379 strcat(pformat, "ld");
382 printf(pformat, statfsbuf->f_bfree);
385 #ifdef __USE_FILE_OFFSET64
386 strcat(pformat, "lld");
388 #if !defined(__linux__) && defined (__GNU__)
389 strcat(pformat, "d");
391 strcat(pformat, "ld");
394 printf(pformat, statfsbuf->f_bavail);
397 #ifdef __USE_FILE_OFFSET64
398 strcat(pformat, "ld");
400 strcat(pformat, "d");
402 printf(pformat, statfsbuf->f_bsize);
405 #ifdef __USE_FILE_OFFSET64
406 strcat(pformat, "lld");
408 #if !defined(__linux__) && defined (__GNU__)
409 strcat(pformat, "d");
411 strcat(pformat, "ld");
414 printf(pformat, statfsbuf->f_files);
417 #ifdef __USE_FILE_OFFSET64
418 strcat(pformat, "lld");
420 #if !defined(__linux__) && defined (__GNU__)
421 strcat(pformat, "d");
423 strcat(pformat, "ld");
426 printf(pformat, statfsbuf->f_ffree);
430 strcat(pformat, "d");
431 printf(pformat, sid);
434 rv = security_sid_to_context(sid, (security_context_t *) &sbuf, &sbuflen);
436 sprintf(sbuf, "<error finding security context %d>", sid);
441 strcat(pformat, "c");
447 /* print stat info */
448 void print_stat(char *pformat, char m, char *filename, void *data, SECURITY_ID_T sid)
452 struct stat *statbuf = (struct stat*)data;
453 struct passwd *pw_ent;
454 struct group *gw_ent;
458 unsigned int sbuflen = sizeof(sbuf);
463 strcat(pformat, "s");
464 printf(pformat, filename);
467 strcat(pformat, "s");
468 if ((statbuf->st_mode & S_IFMT) == S_IFLNK) {
469 if ((i = readlink(filename, linkname, 256)) == -1) {
473 linkname[(i >= 256) ? 255 : i] = '\0';
474 /*printf("\"%s\" -> \"%s\"", filename, linkname);*/
476 printf(pformat, filename);
478 printf(pformat, linkname);
482 printf(pformat, filename);
487 strcat(pformat, "d");
488 printf(pformat, (int)statbuf->st_dev);
491 strcat(pformat, "x");
492 printf(pformat, (int)statbuf->st_dev);
495 strcat(pformat, "d");
496 printf(pformat, (int)statbuf->st_ino);
499 strcat(pformat, "o");
500 printf(pformat, statbuf->st_mode & 07777);
503 print_human_access(statbuf);
506 strcat(pformat, "x");
507 printf(pformat, statbuf->st_mode);
510 print_human_type(statbuf->st_mode);
513 strcat(pformat, "d");
514 printf(pformat, (int)statbuf->st_nlink);
518 strcat(pformat, "d");
519 printf(pformat, sid);
522 rv = security_sid_to_context(sid, (security_context_t *) &sbuf, &sbuflen);
524 sprintf(sbuf, "<error finding security context %d>", sid);
529 strcat(pformat, "d");
530 printf(pformat, statbuf->st_uid);
533 strcat(pformat, "s");
535 pw_ent = getpwuid(statbuf->st_uid);
537 (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
540 strcat(pformat, "d");
541 printf(pformat, statbuf->st_gid);
544 strcat(pformat, "s");
546 gw_ent = getgrgid(statbuf->st_gid);
548 (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
551 strcat(pformat, "x");
552 printf(pformat, major(statbuf->st_rdev));
555 strcat(pformat, "x");
556 printf(pformat, minor(statbuf->st_rdev));
559 #ifdef __USE_FILE_OFFSET64
560 strcat(pformat, "llu");
561 printf(pformat, (unsigned long long)statbuf->st_size);
563 strcat(pformat, "u");
564 printf(pformat, (unsigned int)statbuf->st_size);
568 strcat(pformat, "u");
569 printf(pformat, (unsigned int)statbuf->st_blocks);
572 strcat(pformat, "d");
573 printf(pformat, (int)statbuf->st_blksize);
576 print_human_time(&(statbuf->st_atime));
579 strcat(pformat, "d");
580 printf(pformat, (int)statbuf->st_atime);
583 print_human_time(&(statbuf->st_mtime));
586 strcat(pformat, "d");
587 printf(pformat, (int)statbuf->st_mtime);
590 print_human_time(&(statbuf->st_ctime));
593 strcat(pformat, "d");
594 printf(pformat, (int)statbuf->st_ctime);
597 strcat(pformat, "c");
603 void print_it(char *masterformat, char *filename,
604 void (*print_func)(char*, char, char*, void*, SECURITY_ID_T), void *data, SECURITY_ID_T sid)
606 char *m, *b, *format;
609 /* create a working copy of the format string */
610 format = strdup(masterformat);
619 if ((m = strchr(b, (int)'%')) != NULL)
621 strcpy (pformat, "%");
625 /* copy all format specifiers to our format string */
626 while (isdigit(*m) || strchr("#0-+. I", *m))
631 /* make sure the format specifier is not too long */
632 if (strlen (pformat) > 63)
633 fprintf(stderr, "Warning: Format specifier too long, truncating: %s\n", pformat);
635 strcat (pformat, copy);
645 print_func(pformat, *m, filename, data, sid);
660 /* stat the filesystem and print what we find */
662 do_statfs (char *filename, int terse, int secure, char *format)
664 struct statfs statfsbuf;
665 SECURITY_ID_T sid = -1;
669 if(!is_flask_enabled())
672 i = statfs_secure(filename, &statfsbuf, &sid);
675 i = statfs(filename, &statfsbuf);
688 format = "%n %i %l %t %b %f %a %s %c %d %S %C";
691 format = "%n %i %l %t %b %f %a %s %c %d";
697 format = " File: \"%n\"\n"
698 " ID: %-8i Namelen: %-7l Type: %T\n"
699 "Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
700 "Inodes: Total: %-10c Free: %-10d\n"
701 " SID: %-14S S_Context: %C\n";
704 format = " File: \"%n\"\n"
705 " ID: %-8i Namelen: %-7l Type: %T\n"
706 "Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
707 "Inodes: Total: %-10c Free: %-10d";
711 print_it(format, filename, print_statfs, &statfsbuf, sid);
714 /* stat the file and print what we find */
716 do_stat (char *filename, int link, int terse, int secure, char *format)
720 SECURITY_ID_T sid = -1;
723 if(!is_flask_enabled())
726 i = (link == 1) ? stat_secure(filename, &statbuf, &sid) : lstat_secure(filename, &statbuf, &sid);
729 i = (link == 1) ? stat(filename, &statbuf) : lstat(filename, &statbuf);
743 format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o %S %C";
746 format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
750 /* tmp hack to match orignal output until conditional implemented */
751 i = statbuf.st_mode & S_IFMT;
752 if (i == S_IFCHR || i == S_IFBLK) {
757 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
758 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
759 " Device type: %t,%T\n"
760 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
761 " SID: %-14S S_Context: %C\n"
769 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
770 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
771 " Device type: %t,%T\n"
772 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
783 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
784 "Device: %Dh/%dd\tInode: %-10i Links: %-5h\n"
785 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
786 " SID: %-14S S_Context: %C\n"
794 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
795 "Device: %Dh/%dd\tInode: %-10i Links: %-5h\n"
796 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
803 print_it(format, filename, print_stat, &statbuf, sid);
807 usage (char *progname)
809 fprintf (stderr, "Usage: %s [-l] [-f] [-s] [-v] [-h] [-t] [-c format] file1 [file2 ...]\n", progname);
813 void verbose_usage(char *progname)
815 fprintf(stderr, "Usage: %s [-l] [-f] [-s] [-v] [-h] [-t] [-c format] file1 [file2 ...]\n", progname);
816 fprintf(stderr, "\tformat interpreted sequences for file stat are:\n");
817 fprintf(stderr, "\t\t%%n - File name\n");
818 fprintf(stderr, "\t\t%%N - Quoted File name with dereference if symbolic link\n");
819 fprintf(stderr, "\t\t%%d - Device number in decimal\n");
820 fprintf(stderr, "\t\t%%D - Device number in hex\n");
821 fprintf(stderr, "\t\t%%i - Inode number\n");
822 fprintf(stderr, "\t\t%%a - Access rights in octal\n");
823 fprintf(stderr, "\t\t%%A - Access rights in human readable form\n");
824 fprintf(stderr, "\t\t%%f - raw mode in hex\n");
825 fprintf(stderr, "\t\t%%F - File type\n");
826 fprintf(stderr, "\t\t%%h - Number of hard links\n");
827 fprintf(stderr, "\t\t%%u - User Id of owner\n");
828 fprintf(stderr, "\t\t%%U - User name of owner\n");
829 fprintf(stderr, "\t\t%%g - Group Id of owner\n");
830 fprintf(stderr, "\t\t%%G - Group name of owner\n");
831 fprintf(stderr, "\t\t%%t - Major device type in hex\n");
832 fprintf(stderr, "\t\t%%T - Minor device type in hex\n");
833 fprintf(stderr, "\t\t%%s - Total size, in bytes\n");
834 fprintf(stderr, "\t\t%%b - Number of blocks allocated\n");
835 fprintf(stderr, "\t\t%%o - IO block size\n");
836 fprintf(stderr, "\t\t%%x - Time of last access\n");
837 fprintf(stderr, "\t\t%%X - Time of last access as seconds since Epoch\n");
838 fprintf(stderr, "\t\t%%y - Time of last modification\n");
839 fprintf(stderr, "\t\t%%Y - Time of last modification as seconds since Epoch\n");
840 fprintf(stderr, "\t\t%%z - Time of last change\n");
841 fprintf(stderr, "\t\t%%Z - Time of last change as seconds since Epoch\n");
842 fprintf(stderr, "\t\t%%S - Security ID in SE-Linux\n");
843 fprintf(stderr, "\t\t%%C - Security context in SE-Linux\n");
844 fprintf(stderr, "\tformat interpreted sequences for filesystem stat are:\n");
845 fprintf(stderr, "\t\t%%n - File name\n");
846 fprintf(stderr, "\t\t%%i - File System id in hex\n");
847 fprintf(stderr, "\t\t%%l - Maximum length of filenames\n");
848 fprintf(stderr, "\t\t%%t - Type in hex\n");
849 fprintf(stderr, "\t\t%%T - Type in human readable form\n");
850 fprintf(stderr, "\t\t%%b - Total data blocks in file system\n");
851 fprintf(stderr, "\t\t%%f - Free blocks in file system\n");
852 fprintf(stderr, "\t\t%%a - Free blocks available to non-superuser\n");
853 fprintf(stderr, "\t\t%%s - Optimal transfer block size\n");
854 fprintf(stderr, "\t\t%%c - Total file nodes in file system\n");
855 fprintf(stderr, "\t\t%%S - Security ID in SE-Linux\n");
856 fprintf(stderr, "\t\t%%C - Security context in SE-Linux\n");
857 fprintf(stderr, "\t\t%%d - Free file nodes in file system\n");
863 main (int argc, char *argv[])
865 int c, i, link = 0, fs = 0, terse = 0, secure = 0;
868 while ((c = getopt (argc, argv, "lsfvthc:")) != EOF)
888 printf ("stat version: 3.0\n");
889 verbose_usage(argv[0]);
892 printf ("stat version: 3.0\n");
900 for (i = optind; i < argc; i++)
901 (fs == 0) ? do_stat (argv[i], link, terse, secure, format) :
902 do_statfs (argv[i], terse, secure, format);