Emulating ' find ' command in C - unix

What would be the best way to do this in the C programming language?
find fileName

Look up the POSIX function nftw(). It is designed as a 'new file tree walk' function.
There's a related but not immediately as useful function scandir() which you might use. The selection function might be used to invoke a recursive scan on sub-directories, for example, but nftw() is probably more appropriate.

You could call find from a forked child process and get back find's output from a pipe:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFSIZE 1000
int main(void) {
int pfd[2], n;
char str[BUFSIZE + 1];
if (pipe(pfd) < 0) {
printf("Oups, pipe failed. Exiting\n");
exit(-1);
}
n = fork();
if (n < 0) {
printf("Oups, fork failed. Exiting\n");
exit(-2);
} else if (n == 0) {
close(pfd[0]);
dup2(pfd[1], 1);
close(pfd[1]);
execlp("find", "find", "filename", (char *) 0);
printf("Oups, execlp failed. Exiting\n"); /* This will be read by the parent. */
exit(-1); /* To avoid problem if execlp fails, especially if in a loop. */
} else {
close(pfd[1]);
while ((n = read(pfd[0], str, BUFSIZE)) > 0) {
str[n] = '\0';
printf("%s", str);
}
close(pfd[0]);
wait(&n); /* To avoid the zombie process. */
if (n != 0) {
printf("Oups, find or execlp failed.\n");
}
}
}

That's a complex topic. Have a look at the GNU libc documentation. Then try to scan the current directory using scandir. If that works, you can implement a recursive version, assuming you are talking about the UNIX find command and want to do recursive search for file names.

Related

Trouble with creating an empty file using C programming language in UNIX environment

I have recently started programming in UNIX environment. I need to write a program which creates an empty file with name and size given in the terminal using this commands
gcc foo.c -o foo.o
./foo.o result.txt 1000
Here result.txt means the name of the newly created file, and 1000 means the size of the file in bytes.
I know for sure that lseek function moves the file offset, but the trouble is that whenever I run the program it creates a file with a given name, however the size of the file is 0.
Here is the code of my small program.
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
int fd;
char *file_name;
off_t bytes;
mode_t mode;
if (argc < 3)
{
perror("There is not enough command-line arguments.");
//return 1;
}
file_name = argv[1];
bytes = atoi(argv[2]);
mode = S_IWUSR | S_IWGRP | S_IWOTH;
if ((fd = creat(file_name, mode)) < 0)
{
perror("File creation error.");
//return 1;
}
if (lseek(fd, bytes, SEEK_SET) == -1)
{
perror("Lseek function error.");
//return 1;
}
close(fd);
return 0;
}
If you aren't allowed to use any other functions to assist in creating a "blank" text file, why not change your file mode on creat() then loop-and-write:
int fd = creat(file_name, 0666);
for (int i=0; i < bytes; i++) {
int wbytes = write(fd, " ", 1);
if (wbytes < 0) {
perror("write error")
return 1;
}
}
You'll want to have some additional checks here but, that would be the general idea.
I don't know whats acceptable in your situation but, possibly adding just the write() call after lseek() even:
// XXX edit to include write
if ((fd = creat(file_name, 0666)) < 0) {
perror("File creation error");
//return 1;
}
// XXX seek to bytes - 1
if (lseek(fd, bytes - 1, SEEK_SET) == -1) {
perror("lseek() error");
//return 1;
}
// add this call to write a single byte # position set by lseek
if (write(fd, " ", 1) == -1) {
perror("write() error");
//return 1;
}
close(fd);
return 0;

Count the running process in AIX by it's name in C

Operating system: IBM AIX 5.3
Compiler: xlc
Hello Everyone
I have a project that using C to process some files using multi-processes. The number of sub-processes are mainly depends on the the number of incoming files and the number of current running processes. I need a reliable method to count on how many sub-processes are running at background.
By comparing the efficiency, directly reading /proc directory may have better performance than invoking popen() to execute $ ps -ef | grep blah.
I wrote a function to read psinfo in /proc/pid/psinfo and compare the arugments.
Pseudo code is as follow:
int count = 0;
dp = opendir("/proc");
while (readdir_r(...))
{
if (dir is not a process)
return -1;
if (dir's owner is not current user)
return -2;
if (failed to open "/proc/[pid]/psinfo")
return -3;
if (failed to read "/proc/[pid]/psinfo")
return -4;
if (process's name matches the given pname)
count += 1;
}
return count;
The function generally runs perfectly at single call. However, it returns -2 or -3 or even wrong counts when embedded in while loop.
The function failed to read the attribute of /proc/pid randomly. It tells No such file or directory.
There is also a small chance to get wrong counts at the end. There seems to be an extra process with certain pid but disappeared when printing the current processes using ps.
I think there is any change were made when reading from sub-directory rapidly after parent directory were being listed.
Is there any thing I made wrong or is there any method to avoid the race condition?
Come extra information about psinfo in AIX
http://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.files/doc/aixfiles/proc.htm%23files-proc?lang=en[233]
Here is the full source code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/procfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int countProcess(char *pname)
{
DIR *dir;
int fd;
int pid;
int uid;
int pcounter = 0;
struct psinfo pinfo;
struct dirent entry;
struct dirent *result;
struct stat fsstat;
char path[256];
char process_path[256];
/* Open the /proc directory */
if ((dir = opendir("/proc")) == NULL)
{
return -1;
}
/* Retrieve the current user id */
uid = getuid();
/* Walk through the /proc dir */
for (readdir_r(dir, &entry, &result); result != NULL; readdir_r(dir, &entry, &result))
{
/* See if this is a process, e.g., the dirname is a number
If not, then start off again
*/
if ((pid = atoi(entry.d_name)) == 0)
{
continue;
}
/* Get the attributes of process dir */
snprintf(process_path, sizeof(process_path), "/proc/%s", entry.d_name);
if (stat(process_path, &fsstat) == -1)
{
closedir(dir);
return -2;
}
/* Verify if the process runs by current user
If not, then start off again
*/
if (fsstat.st_uid != uid)
{
continue;
}
/* Open and read from psinfo file */
snprintf(path, sizeof(path), "/proc/%s/psinfo", entry.d_name);
if ((fd = open(path, O_RDONLY)) < 0)
{
close(fd);
closedir(dir);
return -3;
}
if (read(fd, &pinfo, sizeof(pinfo)) < 0)
{
close(fd);
closedir(dir);
return -4;
}
/* String comparison, if same, increase the counter */
if (!strcmp(pinfo.pr_psargs, pname))
{
pcounter++;
}
close(fd);
}
/* returns counter */
closedir(dir);
return pcounter;
}
Update 13/Jan/2015
Thanks to CoreyStup. The race condition can be bypassed by getprocs() function provided in procinfo.h
Here is the code for the solution
#include <stdio.h>
#include <unistd.h>
#include <procinfo.h>
#include <sys/types.h>
int countProcess(const char *pname)
{
struct procsinfo pinfo;
pid_t pid = 0;
uid_t uid;
char args[256];
int index;
int pcounter = 0;
memset(args, 0, sizeof(args));
uid = getuid();
/* Get procsinfo from internal API */
while (0 < getprocs(&pinfo, (int)sizeof(struct procsinfo), NULL, 0, &pid, 1))
{
/* Skip the process that doesn't belong to current user */
if (pinfo.pi_uid != uid)
{
continue;
}
/* Get process arguments */
if (getargs(&pinfo, sizeof(struct procsinfo), args, sizeof(args)) != 0)
{
return -1;
}
/* getargs returns the args list seperated by 0, we need to use space to replace 0 */
for (index = 0; index < 256 - 1 && !(args[index] == 0 && args[index + 1] == 0); index++)
{
if (args[index] == 0)
{
args[index] = ' ';
}
}
if (!strncmp(args, pname, strlen(pname)))
{
pcounter++;
}
}
return pcounter;
}
Try using getprocs(). I find it works better than shelling out with /proc or ps.
I gave an example here: Need help in getting the process name based on the pid in aix

Caught in an infinite loop solving reader writer prob

I am working on reader-writer problem. Algorithm wise, i believe the solution is ok. The only problem that I am facing is opening multiple readers/writer windows using xterm. When I run the program it goes into an infinite loop and it crashed the whole system. It also open multiple xterm windows. It might be silly and simple, but I just don't seem to be able to figure out why? I've been thinking about this since yesterday. How do i fix this problem? The suspected area of conflict is highlighted with ** comments...
#include <unistd.h> /* Symbolic Constants */
#include <sys/types.h> /* Primitive System Data Types */
#include <errno.h> /* Errors */
#include <stdio.h> /* Input/Output */
#include <stdlib.h> /* General Utilities */
#include <pthread.h> /* POSIX Threads */
#include <string.h> /* String handling */
#include <semaphore.h> /* Semaphore */
//Global Variablels
int rc = 0;
int wc = 0;
sem_t m1, m2, m3, w, r; //Semphore
int reader() {
sem_wait(&m3);
sem_wait(&r);
sem_wait(&m1);
rc++;
if(rc == 1) sem_wait(&w);
sem_post(&m1);
sem_post(&r);
sem_post(&m3);
system("xterm -e ./read");
//execlp("xterm", "-e", "./ahor2r", NULL);
sem_wait(&m1);
rc--;
if(rc == 0) sem_post(&w);
sem_post(&m1);
return 0;
}
int writer() {
sem_wait(&m2);
wc++;
if(wc == 1) sem_wait(&r);
sem_post(&m2);
sem_wait(&w);
//system("xterm -e ./write"); //writing is performed
execlp("xterm", "-e", "./ahor2w", NULL);
sem_post(&w);
sem_wait(&m2);
wc--;
if(wc == 0) sem_post(&r);
sem_post(&m2);
return 0;
}
int main() {
int ch;
sem_init(&m1, 0, 1);
sem_init(&m2, 0, 1);
sem_init(&m3, 0, 1);
sem_init(&w, 0, 1);
sem_init(&r, 0, 1);
/*****************************************************************************
**********infinite loop*******************************************************/
while(1) {
printf("\n\nEnter your option\n\n1> Create Reader\n2> Create Writer\n 3> Exit\n\t");
scanf("%d", &ch);
if(ch == 1)
switch(fork()) {
case -1:
perror("Cannot fork a new reader process\n");
break;
case 0:
reader();
}
else if (ch == 2)
switch(fork()) {
case -1:
perror("Cannot fork a new reader process\n");
break;
case 0:
writer();
}
else if (ch == 3) {
sem_destroy(&m1);
sem_destroy(&m2);
sem_destroy(&m3);
sem_destroy(&w);
sem_destroy(&r);
return 0;
}
else printf("INVALID OPTION - no action taken\n");
}
/*****************************************************************************
*****************************************************************************/
return 0;
}
You have two big errors:
You don't create your semaphores in shared memory. So each process gets its own copy of the semaphores, which makes no sense.
You don't create process-shared semaphores. The 0 in sem_init means that the semaphores will not be shared between processes. But fork creates new processes.
If pshared has the value 0, then the semaphore is shared between the threads of a process[.] If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)).

Why grep is taking so much time?

I am using grep to count the number of occurrences of string "^mj" in a file graph.tcl.
The command which i have written is quite easy and you can easily understand.
grep "^mj " mjwork/run/graph.tcl | wc -l
It outputs 46625 but after ~45 min. Can you guys suggest a better approach which could reduce the time?
The following line might make it faster:
$ awk '/^mj/{c++}END{print c}' file
This will process the file only a single time and it will only print the total amount of matches. This is in contrast to your initial case where you ask grep to print everything into a buffer and process that again with wc.
In the end, you could also just do:
$ grep -c '^mj' file
which just returns the total matches. This is probably even faster than the awk version. Awk will, by default, attempt a field splitting, this action is not needed with the above grep.
There are many reasons why your process could be slow, heavy load on the disk, a slow nfs if you use it, extremely long lines to parse, ... without more information on the input file and the system you are running this on, it is hard to say why it is so slow.
Sounds like something up with your machine. Have you enough swap space etc? What does df -h show? As a test, try egrep or fgrep as alternatives to grep.
You should try with this small C program that I just made a minute ago.
#define _FILE_OFFSET_BITS 64
#include <string.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
const char needle[] = "mj";
int main(int argc, char * argv[]) {
int fd, i, res, count;
struct stat st;
char * data;
if (argc != 2) {
fprintf(stderr, "Syntax: %s file\n", *argv);
return 1;
}
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Couldn't open file \"%s\": %s\n", argv[1], strerror(errno));
return 1;
}
res = fstat(fd, &st);
if (res < 0) {
fprintf(stderr, "Failed at fstat: %s\n", strerror(errno));
return 1;
}
if (!S_ISREG(st.st_mode)) {
fprintf(stderr, "File \"%s\" is not a regular file.\n", argv[1]);
return 1;
}
data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (!data) {
fprintf(stderr, "mmap failed!: %s\n", strerror(errno));
return 1;
}
count = 0;
for (i = 0; i < st.st_size; i++) {
// look for string:
if (i + sizeof needle - 1 < st.st_size
&& !memcmp(data + i, needle, sizeof needle - 1)) {
count++;
i += sizeof needle - 1;
}
while (data[i] != '\n' && i < st.st_size)
i++;
}
printf("%d\n", count);
return 0;
}
Compile it with: gcc grepmj.c -o grepmj -O2

UNIX IPC C program only parent process can write to file, child not working

I need to use Signal to write UNIX Interprocess communication program in C. I want a parent process and child process to write to a same file.
The result only show parent written text. I can use either BSD or System V. Please help
#include <stdio.h> /* basic I/O routines. */
#include <unistd.h> /* define fork(), etc. */
#include <sys/types.h> /* define pid_t, etc. */
#include <sys/wait.h> /* define wait(), etc. */
#include <signal.h>
int myFlag = 0;
void myHandler(int);
int child_pid;
int main()
{
//oldmask = sigblock(sigmask(SIGUSR1));
sighold(SIGUSR1);
sighold(SIGINT);
/* critical region */
signal (SIGUSR1, myHandler);
sigrelse(SIGUSR1);
sigrelse(SIGINT);
child_pid = fork();
if (child_pid==0) {
for ( ; ; ) {
while(myFlag == 0)
sigpause(0);
sigblock (sigmask(SIGUSR1));
myFlag = 0;
FILE *fp=fopen("test","w");
fwrite("child",1,6,fp);
fclose(fp);
kill(getppid(),SIGUSR1);
}
}
if (child_pid>0){
FILE *fp;
fp=fopen("test","w");
fwrite("parent",1,6,fp);
fclose(fp);
for ( ; ; ) {
while(myFlag == 0)
sigpause(0);
sigblock (sigmask(SIGUSR1));
myFlag = 0;
fp=fopen("test","w");
fwrite("parent",1,6,fp);
fclose(fp);
}
kill(child_pid, SIGUSR1);
//kill ()-child_pid ;
}
exit(0);
}
void myHandler(int sigNo) {
myFlag = 1;
//signal (SIGUSR1, myHandler);
}
You should start by opening the file in append mode rather than write mode:
fp = fopen("test", "a");
That will position the write position of fp at the end of file rather than the beginning. When you open with "w", you truncate the file and start writing from position 0:
w or wb
Truncate to zero length or create file for writing.
Then you might want to think about file locking to keep the two processes from writing to the file at the same time.
Also, your child process writes out the nul terminator:
fwrite("child", 1, 6, fp);
but your parent process doesn't:
fwrite("parent", 1, 6, fp);
That may or may not be your intention but it does look odd.
Your logic is flawed. The parent process does not signal the child process before it waits for the child process to signal it. The child process waits for the parent process to signal it before writing the file and signaling the parent process.
This means after you write the file in the parent both the parent and child are stuck in busy loops waiting for the other one to do something.
Also, while I don't think this is a problem in your code since the call to sigpause(0); should cause the compiler to believe that global variables may have changed and need to be reloaded, in other situations you might want to declare myFlag as volatile int myFlag;. This forces the compiler to read or write its value from memory every time you reference it.
Lastly, of course, your programs will simply re-write over the same bytes repeatedly because you open the files in "w" (write) mode instead of "a" (append) mode.
Here's a program that accomplishes what you want using POSIX standard calls and techniques instead of the old deprecated obsolete calls you were using:
#include <stdio.h> /* basic I/O routines. */
#include <unistd.h> /* define fork(), etc. */
#include <sys/types.h> /* define pid_t, etc. */
#include <sys/wait.h> /* define wait(), etc. */
#include <signal.h>
#include <stdlib.h>
volatile sig_atomic_t myFlag = 0;
void myHandler(int);
int child_pid;
int main()
{
signal (SIGUSR1, myHandler);
child_pid = fork();
if (child_pid==0) {
for ( ; ; ) {
while(myFlag == 0)
;
{
sigset_t oldmask;
sigset_t usr1;
sigemptyset(&oldmask);
sigemptyset(&usr1);
sigaddset(&usr1, SIGUSR1);
sigprocmask(SIG_BLOCK, &usr1, &oldmask);
myFlag = 0;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
FILE *fp=fopen("test","a");
fwrite("child\n",1,6,fp);
fclose(fp);
kill(getppid(),SIGUSR1);
}
}
if (child_pid>0){
FILE *fp;
fp=fopen("test","a");
fwrite("parent\n",1,7,fp);
fclose(fp);
for ( ; ; ) {
kill(child_pid, SIGUSR1);
//kill ()-child_pid ;
while(myFlag == 0)
;
{
sigset_t oldmask;
sigset_t usr1;
sigemptyset(&oldmask);
sigemptyset(&usr1);
sigaddset(&usr1, SIGUSR1);
sigprocmask(SIG_BLOCK, &usr1, &oldmask);
myFlag = 0;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
fp=fopen("test","a");
fwrite("parent\n",1,7,fp);
fclose(fp);
}
}
exit(0);
}
void myHandler(int sigNo) {
myFlag = 1;
//signal (SIGUSR1, myHandler);
}

Resources