I'm learning C and today I wrote a program that displays info about my hardware on ubuntu.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ch, file_name[25] = "/proc/scsi/scsi";
FILE *fp;
fp = fopen(file_name,"r"); // read mode
if( fp == NULL )
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name);
while( ( ch = fgetc(fp) ) != EOF )
printf("%c",ch);
fclose(fp);
return 0;
}
For me it looked like this
$ cc driveinfo.c;./a.out
The contents of /proc/scsi/scsi file are :
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
Vendor: ATA Model: WDC WD2500JS-75N Rev: 10.0
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi1 Channel: 00 Id: 00 Lun: 00
Vendor: ATA Model: ST3250824AS Rev: 3.AD
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi2 Channel: 00 Id: 00 Lun: 00
Vendor: TSSTcorp Model: DVD+-RW TS-H653A Rev: D300
Type: CD-ROM ANSI SCSI revision: 05
Host: scsi3 Channel: 00 Id: 00 Lun: 00
Vendor: Optiarc Model: DVD-ROM DDU1681S Rev: 102A
Type: CD-ROM ANSI SCSI revision: 05
Host: scsi4 Channel: 00 Id: 00 Lun: 00
Vendor: Lexar Model: USB Flash Drive Rev: 1100
Type: Direct-Access ANSI SCSI revision: 00
Host: scsi5 Channel: 00 Id: 00 Lun: 00
Vendor: WD Model: 5000AAKB Externa Rev: l108
Type: Direct-Access ANSI SCSI revision: 00
Can it run on other unices e.g. bsd? How can I make it run on ms-windows? Can I query the hardware directly instead of the file /proc/scsi/scsi
?
Update
Thanks a lot. Here are my updates.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int ch;
char file_name[25] = "/proc/scsi/scsi";
FILE *fp;
fp = fopen(file_name,"r"); // read mode
if (fp == NULL)
{
perror(file_name);
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name);
while ((ch = fgetc(fp)) != EOF)
putchar(ch);
fclose(fp);
return 0;
}
Test run
$ cc driveinfo.c;./a.out
The contents of /proc/scsi/scsi file are :
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
Vendor: ATA Model: WDC WD2500JS-75N Rev: 10.0
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi1 Channel: 00 Id: 00 Lun: 00
Vendor: ATA Model: ST3250824AS Rev: 3.AD
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi2 Channel: 00 Id: 00 Lun: 00
Vendor: TSSTcorp Model: DVD+-RW TS-H653A Rev: D300
Type: CD-ROM ANSI SCSI revision: 05
Host: scsi3 Channel: 00 Id: 00 Lun: 00
Vendor: Optiarc Model: DVD-ROM DDU1681S Rev: 102A
Type: CD-ROM ANSI SCSI revision: 05
Host: scsi4 Channel: 00 Id: 00 Lun: 00
Vendor: Lexar Model: USB Flash Drive Rev: 1100
Type: Direct-Access ANSI SCSI revision: 00
Host: scsi5 Channel: 00 Id: 00 Lun: 00
Vendor: WD Model: 5000AAKB Externa Rev: l108
Type: Direct-Access ANSI SCSI revision: 00
Latest version
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int ch;
char file_name[] = "/proc/scsi/scsi";
char cpu_file_name[] = "/proc/cpuinfo";
FILE *fp;
FILE *cpu_fp;
fp = fopen(file_name,"r"); // read mode
cpu_fp = fopen(cpu_file_name,"r"); // read mode
if (fp == NULL)
{
perror(file_name);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
{
putchar(ch);
}
fclose(fp);
if (cpu_fp == NULL)
{
perror(cpu_file_name);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(cpu_fp)) != EOF)
{
putchar(ch);
}
fclose(cpu_fp);
return 0;
}
Test
$ cat cpu-disk-info.c;clang -Wconversion cpu-disk-info.c;./a.out
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int ch;
char file_name[] = "/proc/scsi/scsi";
char cpu_file_name[] = "/proc/cpuinfo";
FILE *fp;
FILE *cpu_fp;
fp = fopen(file_name,"r"); // read mode
cpu_fp = fopen(cpu_file_name,"r"); // read mode
if (fp == NULL)
{
perror(file_name);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
{
putchar(ch);
}
fclose(fp);
if (cpu_fp == NULL)
{
perror(cpu_file_name);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(cpu_fp)) != EOF)
{
putchar(ch);
}
fclose(cpu_fp);
return 0;
}
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
Vendor: ATA Model: WDC WD2500JS-75N Rev: 10.0
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi1 Channel: 00 Id: 00 Lun: 00
Vendor: ATA Model: ST3250824AS Rev: 3.AD
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi2 Channel: 00 Id: 00 Lun: 00
Vendor: TSSTcorp Model: DVD+-RW TS-H653A Rev: D300
Type: CD-ROM ANSI SCSI revision: 05
Host: scsi3 Channel: 00 Id: 00 Lun: 00
Vendor: Optiarc Model: DVD-ROM DDU1681S Rev: 102A
Type: CD-ROM ANSI SCSI revision: 05
Host: scsi4 Channel: 00 Id: 00 Lun: 00
Vendor: Lexar Model: USB Flash Drive Rev: 1100
Type: Direct-Access ANSI SCSI revision: 00
Host: scsi5 Channel: 00 Id: 00 Lun: 00
Vendor: WD Model: 5000AAKB Externa Rev: l108
Type: Direct-Access ANSI SCSI revision: 00
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz
stepping : 6
microcode : 0xc6
cpu MHz : 2128.073
cache size : 2048 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 10
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx lm constant_tsc arch_perfmon pebs bts nopl aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm lahf_lm dtherm tpr_shadow
bogomips : 4256.14
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz
stepping : 6
microcode : 0xc6
cpu MHz : 2128.073
cache size : 2048 KB
physical id : 0
siblings : 2
core id : 1
cpu cores : 2
apicid : 1
initial apicid : 1
fpu : yes
fpu_exception : yes
cpuid level : 10
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx lm constant_tsc arch_perfmon pebs bts nopl aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm lahf_lm dtherm tpr_shadow
bogomips : 4256.00
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
dev@dev-OptiPlex-745:~$
Very latest version with new function
#include <stdio.h>
#include <stdlib.h>
void info(char file_name[])
{
int ch;
FILE *fp;
fp = fopen(file_name,"r");
// read mode
if (fp == NULL)
{
perror(file_name);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
{
putchar(ch);
}
fclose(fp);
}
int main(int argc, char **argv)
{
info("/proc/scsi/scsi");
info("/proc/cpuinfo");
return 0;
}
Test
$ cat cpu-disk-info.c;clang -Wconversion cpu-disk-info.c;./a.out
#include <stdio.h>
#include <stdlib.h>
void info(char file_name[])
{
int ch;
FILE *fp;
fp = fopen(file_name,"r");
// read mode
if (fp == NULL)
{
perror(file_name);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
{
putchar(ch);
}
fclose(fp);
}
int main(int argc, char **argv)
{
info("/proc/scsi/scsi");
info("/proc/cpuinfo");
return 0;
}
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
Vendor: ATA Model: WDC WD2500JS-75N Rev: 10.0
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi1 Channel: 00 Id: 00 Lun: 00
Vendor: ATA Model: ST3250824AS Rev: 3.AD
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi2 Channel: 00 Id: 00 Lun: 00
Vendor: TSSTcorp Model: DVD+-RW TS-H653A Rev: D300
Type: CD-ROM ANSI SCSI revision: 05
Host: scsi3 Channel: 00 Id: 00 Lun: 00
Vendor: Optiarc Model: DVD-ROM DDU1681S Rev: 102A
Type: CD-ROM ANSI SCSI revision: 05
Host: scsi4 Channel: 00 Id: 00 Lun: 00
Vendor: Lexar Model: USB Flash Drive Rev: 1100
Type: Direct-Access ANSI SCSI revision: 00
Host: scsi5 Channel: 00 Id: 00 Lun: 00
Vendor: WD Model: 5000AAKB Externa Rev: l108
Type: Direct-Access ANSI SCSI revision: 00
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz
stepping : 6
microcode : 0xc6
cpu MHz : 2128.073
cache size : 2048 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 10
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx lm constant_tsc arch_perfmon pebs bts nopl aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm lahf_lm dtherm tpr_shadow
bogomips : 4256.14
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz
stepping : 6
microcode : 0xc6
cpu MHz : 2128.073
cache size : 2048 KB
physical id : 0
siblings : 2
core id : 1
cpu cores : 2
apicid : 1
initial apicid : 1
fpu : yes
fpu_exception : yes
cpuid level : 10
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx lm constant_tsc arch_perfmon pebs bts nopl aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm lahf_lm dtherm tpr_shadow
bogomips : 4256.00
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
2 strategies implemented
I tried implementing 1024 bytes i/o for 2 strategies. I'm not sure but the chunkinfo function can be better. I didn't find the source to the unix program cat but I try something similar.
#include <stdio.h>
#include <stdlib.h>
#define CHUNK 1024 /* read 1024 bytes at a time */
void info(char file_name[])
{
int ch;
FILE *fp;
fp = fopen(file_name,"r");
// read mode
if (fp == NULL)
{
perror(file_name);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
{
putchar(ch);
}
fclose(fp);
}
void chunkinfo(char file_name[])
{
char buf[CHUNK];
FILE *file;
size_t nread;
file = fopen(file_name, "r");
if (file) {
while ((nread = fread(buf, 1, sizeof buf, file)) > 0)
fwrite(buf, 1, nread, stdout);
if (ferror(file)) {
/* deal with error */
}
fclose(file);
}
}
int main(int argc, char **argv)
{
info("/proc/scsi/scsi");
chunkinfo("/proc/cpuinfo");
return 0;
}
For the record I also review how a cat.c implementation does it:
#include <sys/param.h>
#include <sys/stat.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern char *__progname;
int bflag, eflag, nflag, sflag, tflag, vflag;
int rval;
char *filename;
void cook_args(char *argv[]);
void cook_buf(FILE *);
void raw_args(char *argv[]);
void raw_cat(int);
int main(int argc, char *argv[])
{
int ch;
setlocale(LC_ALL, "");
while ((ch = getopt(argc, argv, "benstuv")) != -1)
switch (ch) {
case 'b':
bflag = nflag = 1; /* -b implies -n */
break;
case 'e':
eflag = vflag = 1; /* -e implies -v */
break;
case 'n':
nflag = 1;
break;
case 's':
sflag = 1;
break;
case 't':
tflag = vflag = 1; /* -t implies -v */
break;
case 'u':
setbuf(stdout, NULL);
break;
case 'v':
vflag = 1;
break;
default:
(void)fprintf(stderr,
"usage: %s [-benstuv] [-] [file ...]\n", __progname);
exit(1);
/* NOTREACHED */
}
argv += optind;
if (bflag || eflag || nflag || sflag || tflag || vflag)
cook_args(argv);
else
raw_args(argv);
if (fclose(stdout))
err(1, "stdout");
exit(rval);
/* NOTREACHED */
}
void cook_args(char **argv)
{
FILE *fp;
fp = stdin;
filename = "stdin";
do {
if (*argv) {
if (!strcmp(*argv, "-"))
fp = stdin;
else if ((fp = fopen(*argv, "r")) == NULL) {
warn("%s", *argv);
rval = 1;
++argv;
continue;
}
filename = *argv++;
}
cook_buf(fp);
if (fp != stdin)
(void)fclose(fp);
} while (*argv);
}
void cook_buf(FILE *fp)
{
int ch, gobble, line, prev;
line = gobble = 0;
for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
if (prev == '\n') {
if (sflag) {
if (ch == '\n') {
if (gobble)
continue;
gobble = 1;
} else
gobble = 0;
}
if (nflag && (!bflag || ch != '\n')) {
(void)fprintf(stdout, "%6d\t", ++line);
if (ferror(stdout))
break;
}
}
if (ch == '\n') {
if (eflag && putchar('$') == EOF)
break;
} else if (ch == '\t') {
if (tflag) {
if (putchar('^') == EOF || putchar('I') == EOF)
break;
continue;
}
} else if (vflag) {
if (!isascii(ch)) {
if (putchar('M') == EOF || putchar('-') == EOF)
break;
ch = toascii(ch);
}
if (iscntrl(ch)) {
if (putchar('^') == EOF ||
putchar(ch == '\177' ? '?' :
ch | 0100) == EOF)
break;
continue;
}
}
if (putchar(ch) == EOF)
break;
}
if (ferror(fp)) {
warn("%s", filename);
rval = 1;
clearerr(fp);
}
if (ferror(stdout))
err(1, "stdout");
}
void raw_args(char **argv)
{
int fd;
fd = fileno(stdin);
filename = "stdin";
do {
if (*argv) {
if (!strcmp(*argv, "-"))
fd = fileno(stdin);
else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
warn("%s", *argv);
rval = 1;
++argv;
continue;
}
filename = *argv++;
}
raw_cat(fd);
if (fd != fileno(stdin))
(void)close(fd);
} while (*argv);
}
void raw_cat(int rfd)
{
int wfd;
ssize_t nr, nw, off;
static size_t bsize;
static char *buf = NULL;
struct stat sbuf;
wfd = fileno(stdout);
if (buf == NULL) {
if (fstat(wfd, &sbuf))
err(1, "stdout");
bsize = MAX(sbuf.st_blksize, BUFSIZ);
if ((buf = malloc(bsize)) == NULL)
err(1, "malloc");
}
while ((nr = read(rfd, buf, bsize)) != -1 && nr != 0)
for (off = 0; nr; nr -= nw, off += nw)
if ((nw = write(wfd, buf + off, (size_t)nr)) == 0 ||
nw == -1)
err(1, "stdout");
if (nr < 0) {
warn("%s", filename);
rval = 1;
}
}