lstat() st_blocks outputting incorrect value - c

Whenever I run my program for every directory 8 is output even when I use ls-ls to check the actual size of each directory.
Im trying to print the st_blocks of all the directories the user enters
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char**argv)
{
struct stat path_stat;
int i;
int size=0;
for (i=1; i <argc; i++){
if (lstat(argv[i], &path_stat)) {
perror(argv[i]);
} else {
if (S_ISDIR(path_stat.st_mode)){
size=path_stat.st_blocks;
printf("%d %s \n",size,argv[i]);
}
}
}
return(0);
}

st_blocks is the number of 512 byte blocks allocated to the directory node. 8x512 = 4096 bytes = 1 block for a typical modern filesystem seems correct.
It will not tell you the total size of files within the folder or similar information, if that is what you are hoping to obtain.
For more information:
https://askubuntu.com/questions/186813/why-does-every-directory-have-a-size-4096-bytes-4-k

Related

How to print hard link numbers with file names?

I'm trying to make a program
printing files that has the same inode numbers
printing the amount of hard links in the current directory.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
int main() {
DIR *dp;
dp = opendir(".");
struct dirent *dent1, *dent2;
while((dent1 = readdir(dp))) {
while((dent2 = readdir(dp))) {
struct stat buf;
if(stat(dent1->d_name, &buf)) {
perror("stat");
exit(1);
}
if((dent1->d_ino == dent2->d_ino) && (dent1->d_name != dent2->d_name) {
printf("---Same inode files---\n");
printf("%s\n", dent1->d_name);
printf("%s\n", dent2->d_name);
printf("Number of hard links = %o\n", (unsigned int)buf.st_nlink);
}
}
}
closedir(dp);
return 0;
}
This is my code I wrote.
I used two loops to compare each files inode numbers.
There was no error in the program. But it didn't work well as I expected.
There were 3 hard links in the current directory, but it only printed one of them.
I know my coding skills are not good, but I did my best and this is as far as I can get on my own.
Is there anything wrong with my program?
Do I have to add something more?
Is my code inefficient?

FILE I/O operations. Clearing the elements of an structure

I'm a begginer but I'm basically creating a program that opens a binary file containing 'parts' structure, reads the structure
into an array, sets the on_hand member of each structure to 0, and then writes the structure back to the file. Here's my code:
invclear.c
/* Modifies a file of part records by setting the quantity
on hand to a zero for all records */
#include <stdio.h>
#include <stdlib.h>
#define NAME_LEN 25
#define MAX_PARTS 100
struct part { //size= 36 bytes (2 holes in between number and name[] array
int number;
char name[NAME_LEN+1];
int on_hand;
}inventory[MAX_PARTS];
int num_parts;
int main()
{
FILE *fp;
int i;
if((fp=fopen("clear_sample.c", "rb+")) == NULL)
{
fprintf(stderr, "Can't open inventory file.\n");
exit(EXIT_FAILURE);
}
num_parts = fread(inventory, sizeof(struct part), MAX_PARTS, fp); //reads the contents
for(i=0; i<num_parts; i++)
inventory[i].on_hand=0; //clears them
rewind(fp); //sets file position at beggining
fwrite(inventory,sizeof(struct part), num_parts, fp);
fclose(fp);
return 0;
}
clear_sample.c
#include <stdio.h>
#include <stdlib.h>
#define NAME_LEN 25
#define MAX_PARTS 100
struct part {
int number;
char name[NAME_LEN+1];
int on_hand;
}inventory[MAX_PARTS]={0};
int main()
{
int i;
int num_parts;
for(i=1;i<=15;i++)
inventory[i].on_hand=i;
for(i=1;i<=15;i++)
printf("%d\n",inventory[i].on_hand);
return 0;
}
It runs without errors but unfortunately it's not clearing the on_hand variable to 0, in fact it's deleting almost the whole file. This is the modified clear_sample.c file that I get:
#include <stdio.h>
#include <st
Any ideas into why am I doing wrong would be greatly appreciated.
You have been misled by whatever tool you used to inspect the resulting file. It is not
#include <stdio.h>
#include <st
In fact it is
#include <stdio.h>
#include <std^#^#^#^#h>
#define NAME_LEN 25
#define ^#^#^#^#PARTS 100
struct part {
int^#^#^#^#ber;
char name[NAME_LEN+1];
^#^#^#^#int on_hand;
}inventory[MAX_^#^#^#^#S]={0};
int main()
{
int i^#^#^#^# int num_parts;
for(i=1;i<^#^#^#^#i++)
inventory[i].on_han^#^#^#^#
for(i=1;i<=15;i++)
^#^#^#^#ntf("%d\n",inventory[i].on_hand)^#^#^#^# return 0;
}
All those ^# are binary zero bytes, corresponding to zeroes you've put into on_hand.
As mentioned in comments, to test your program prepare a file which does obey the format you expect.

Segmentation Fault outside the loop only

Using C on Linux, I'm writing a code that stores all the information about the files in a directory using function stat() and prints them on the Terminal
The algorithm is quite simple, I made a structure array of "files" and dynamically allocated them. The structure contains a char array (string) so I dynamically allocated it too.
The thing is .. the dynamic allocation works fine but if I'm inside the while loop I can access the other element inside the structure - which is a structure stat object - but if I access it after the loop finishes, it gives me "Segmentation Fault"!
Here's the code
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <dirent.h>
struct file{
char* name;
struct stat fbuf;
};
int main(int argc, char **argv)
{
char* dir=NULL;
int k;
dir=(char *)malloc(strlen(argv[argc-1])+1);
dir=argv[argc-1];
strcpy(dir,argv[argc-1]);
DIR *curr_dir;
struct dirent *dir_inode;
int i,j=0;
char* sum=NULL;
struct file* files=NULL;
if ((curr_dir = opendir(dir)) == NULL) {
fprintf(stderr, "Can't Open %s\n", argv[1]);
exit(2);
}
while (((dir_inode = readdir(curr_dir))) != NULL) {
files=(struct file*) realloc(files,((j)+1)*(sizeof(char*)+sizeof(struct stat))); // Structure array reallocation
(files+(j))->name=(char *)(malloc(strlen(dir_inode->d_name)+1));//name allocation
for(i=0;i<strlen(dir_inode->d_name);i++)
(files+(j))->name[i]=dir_inode->d_name[i];//name storage
(files+(j))->name[i]='\0';
sum= (char *) malloc(strlen(dir)+strlen(dir_inode->d_name)+2);//To add file name to its directory
for(i=0;i<strlen(dir);i++)
sum[i]=dir[i];
sum[i]='/';
i++;
for(k=0;dir_inode->d_name[k]!='\0';k++)
sum[i+k]=dir_inode->d_name[k];
sum[i+k]='\0';//file name with directory in sum
if( stat(sum,&((files+j)->fbuf)) == -1){ // the function gets information from the file name and stores them in fbuf
printf("error stat\n");
exit(1);
}
free(sum);
if( S_ISDIR( ( (files+(j))->fbuf ).st_mode ) ){
printf("d");
}
else {
printf("-");
}
//Here the output appears fine
//The output depends on accessing fbuf in files array
printf("statOK\n");
(j)++; // index
}
printf("%d %d %d\n",files,j,files+1);
printf("%d\n",j);
printf("\n\n\n\n");
for(i=0;i<j;i++){
printf("%s\n",(files+i)->name);
printf("%d\n",files);
//Starting from here, same syntax but outside the loop it gives the error
if( S_ISDIR( ( (files+i)->fbuf ).st_mode ) ){
printf("d");
else {
printf("-");
}
}
free(files);
free(dir);
closedir(curr_dir);
exit(1);
}
The code isn't complete yet but all what I want is to access the fbuf outside the loop, then I can complete it
Any ideas?
Bad size assumption
This allocation is wrong:
files=(struct file*) realloc(files,((j)+1)*(sizeof(char*)+sizeof(struct stat)));
Here, you assumed that the size of struct file was the sum of the sizes of its two components. But in fact, you don't know how that structure is packed and aligned, so the size of struct file could be larger than what you thought. You should just be using sizeof(struct file) instead:
files=(struct file*) realloc(files,(j+1)*(sizeof(struct file)));

Counting different words from a text input

I want to do a code that searches a txt file and returns the number of different words and how many times they appear on the text.
I' trying to do that, but I'm having a problem on comparing the word read from the input with the words already read. So I'm doing a code that adds a word to the vector of words if is new, and if it isn't, it increments by 1 the word count. But when I'm comparing the words, it doesn't states that they're equal even when they aren't.
By exemple: txt is filled with:
test test test.
test test test.
("test." =/= from "test"). And it return 7 different words with 3 being NULL, "3 test" and 1 "test." . That should return 2 words and count 4 on test and count 2 on test.
Can anybody see what is wrong with my code?
#define MAX_PALAVRAS 1024
#define MAX_TAM_PALAVRA 32
typedef struct ocorrencia_ {
char palavra[MAX_TAM_PALAVRA];
int pos;
int num_ocorrencias;
}ocorrencia;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
int main (int argc, char * argv[]){
ocorrencia palavras[MAX_PALAVRAS];
int i,palavras_diferentes=0,palavra_atual=0;
char aux[MAX_TAM_PALAVRA];
bool nova_palavra=true;
for (i=0;i<MAX_PALAVRAS;i++){
palavras[i].pos=-1;
palavras[i].num_ocorrencias=0;
}
FILE * D = fopen("input.txt","r");
while (!feof(D)){
char aux2[MAX_TAM_PALAVRA];
fscanf(D,"%s",aux);
for (i=0;i<palavras_diferentes;i++){
if (strcmp(palavras[palavras_diferentes].palavra,aux)==0){
nova_palavra=false;
break;
}
palavra_atual++;
}
if (nova_palavra){
strcpy(palavras[palavra_atual].palavra,aux);
palavras_diferentes++;
}
palavras[palavra_atual].num_ocorrencias++;
printf("%s\n",palavras[palavra_atual].palavra);
}
fclose (D);
printf("diferent words=%i\n",palavras_diferentes);
printf("success!\n");
return (EXIT_SUCCESS);
}
Thanks for taking or time reading or trying to help!
Following my comments, here are a few changes that may help you :
-Set palavra_atual to 0 and nova_palavra to true at the beginning of the while loop.
-Test the return of fscanf, add something like if(fscanf(D,"%s",aux)==1){...}
-Test all words ! if (strcmp(palavras[i].palavra,aux)==0)
Here goes the code :
#define MAX_PALAVRAS 1024
#define MAX_TAM_PALAVRA 32
typedef struct ocorrencia_ {
char palavra[MAX_TAM_PALAVRA];
int pos;
int num_ocorrencias;
}ocorrencia;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
int main (int argc, char * argv[]){
ocorrencia palavras[MAX_PALAVRAS];
int i,palavras_diferentes=0,palavra_atual=0;
char aux[MAX_TAM_PALAVRA];
bool nova_palavra=true;
for (i=0;i<MAX_PALAVRAS;i++){
palavras[i].pos=-1;
palavras[i].num_ocorrencias=0;
}
FILE * D = fopen("input.txt","r");
while (!feof(D)){
palavra_atual=0;
nova_palavra=true;
char aux2[MAX_TAM_PALAVRA];
if(fscanf(D,"%s",aux)==1){
for (i=0;i<palavras_diferentes;i++){
if (strcmp(palavras[i].palavra,aux)==0){
nova_palavra=false;
break;
}
palavra_atual++;
}
if (nova_palavra==true){
printf("new word %d %s\n",palavra_atual,aux);
strcpy(palavras[palavra_atual].palavra,aux);
palavras_diferentes++;
}
palavras[palavra_atual].num_ocorrencias++;
printf("%s\n",palavras[palavra_atual].palavra);
}
}
fclose (D);
printf("diferent words=%i\n",palavras_diferentes);
printf("success!\n");
return (EXIT_SUCCESS);
}
You will be interesseted by ispunct() of ctypes.h here

Passing command line arguments through a C setuid wrapper to another script

I have the following c setuid wrapper:
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
main( int argc, char ** argv ) {
struct passwd *pwd;
char user[] = "cvmfs-test";
pwd = getpwnam(user);
setuid(pwd->pw_uid);
system(argv[1]);
}
I can call my perl script with ./cwrapper perlscript.pl.
I would like to do ./cwrapper perlscript.pl --option1 --option2 --option3 and elaborate all arguments inside the perl script with GetOptions. How should I change my wrapper?
There is also a nice solution which does not need any allocation, is able to deal with arbitrary long commands and does not imply running useless processes because it does not use system. Moreover with the following solution you get the exit code of the spawned process for free.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#define SETUIDUSER "foobar"
int main(int argc, char **argv) {
struct passwd *pwd;
char user[] = SETUIDUSER;
pwd = getpwnam(user);
// success test needed here
setuid(pwd->pw_uid);
// success test needed here
if (argc < 2)
return 1;
execvp(argv[1], &argv[1]);
return 42;
}
Here is a version dealing with a variable number of arguments. Please note that your syscalls should be tested to ensure everything is going OK.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#define CMDMAXLGTH 4096
#define SETUIDUSER "testuser"
int main( int argc, char ** argv ) {
struct passwd *pwd;
char user[] = SETUIDUSER;
char buf[CMDMAXLGTH];
char *p = buf;
int i = 1;
pwd = getpwnam(user);
// success test needed here
setuid(pwd->pw_uid);
// success test needed here
memset (buf, 0, sizeof(buf));
while (argv[i]) {
p += sprintf(p, " %s", argv[i++]);
}
system(buf);
return 0;
}
You should use sprintf to build a character string with your options, then pass this string to system:
char command [100];
sprintf (command, "./cwrapper %s --%s --%s --%s", program_name,option1,option2,
option3);
system(command);
Update: this approach assumes a fixed number of arguments, and looking back at your question, I see that may not be the case.
Ignore the argv[0] because is the name of the c program and use all the other. You can calculate (strlen) the required memory to assemble a new string, malloc() the memory for the new string and then build your new string by concatenating all the argv (strcat). Or for a fixed length approach, follow #dan1111 answer.

Resources