March 2006
In the first part of this series a simple version of a service utility originally written in Perl was rewritten in C. The first version of the C service utility had a few lingering items. The question to be hopefully answered in this text is after fixing a few of these, was it worth the effort?
To start, a slew of new functions are added:
size_t strlcat (char *, const char *, size_t); size_t strlcpy(char *, const char *, size_t); int dirlist(char *); void usage(void);
This is a simple verbose copy of the OpenBSD strl function of the same name. Note that the license would now have to reflect this change:
size_t strlcat (char *dst, const char *src, size_t dst_sz)
{
size_t len = strlen(dst);
if (dst_sz < len)
return len + strlen(src);
return len + strlcpy (dst + len, src, dst_sz - len);
}
The next simplest function added is the usage message.
void usage(void)
{
printf("Usage: service service-name operation\n");
printf("Usage: service [list|show]\n");
printf(" list - list init scripts\n");
printf(" show - show init directory path\n");
}
nothing too fancy there, next yet another copy, right from the GNU programming manual.
int dirlist (char * dir)
{
DIR *dp;
struct dirent *ep;
int i;
i = 0;
dp = opendir(dir);
if (dp != NULL) {
while (ep = readdir (dp)) {
if (i > 1)
printf("%s\n", ep->d_name);
i++;
}
(void) closedir (dp);
} else
perror ("Could not open directory for reading");
return 0;
}
This version is somewhat different, but it makes for a good starting point. Note that it would be a lot nicer if it used well formatted printing.
With all of the new stuff
added, a lot of the
main() program had to be reworked. Some new includes
were tossed in but otherwise the data structure used in the first
one remains. Now the new top part of main():
int main (int argc, char **argv)
{
int x, c;
int show;
char sh_cmd[PATH_MAX];
c = 1;
show = 0;
We set up a counter and show is whether or not the
show command is going to be passed:
if (strcmp(argv[1], "show") == 0)
show++;
In the main while loop, if show is specified, it
simply prints out the full path to the service.
x = 0;
while (x <= (sizeof(init_pth)/3)) {
if (check_handle(init_pth[x]) == 0) {
strcpy(sh_cmd, init_pth[x]);
if (show) {
printf("%s\n", init_pth[x]);
return 0;
}
break;
} else
x++;
}
Finally, check for the list and usage
commands, put the full command together, and run it:
if (strcmp(argv[1], "list") == 0) {
dirlist(sh_cmd);
return 0;
} else if (strcmp(argv[1], "usage") == 0) {
usage();
return 0;
}
if (argc <= 2) {
printf("Syntax error\n");
usage();
exit(1);
}
strlcat(sh_cmd, argv[c], sizeof(sh_cmd));
strcat(sh_cmd, " ");
strlcat(sh_cmd, argv[++c], sizeof(sh_cmd));
system(sh_cmd);
return 0;
}
Not much and it still lacks some of the functionality of the Perl version.
In summary, if there is a very compelling reason (like someone actually doesn't have Perl loaded) the rewrite is exactly what was first stated - a good exercise - otherwise not really worth the time. This opens the door up for discussion about whether or not prototyping in one language for another is a good idea.
Special thanks go to Geffrey Velasquez and Matt B
for
some corrections in the main while loop.