utils CVS: src/ln.c 1.17
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
typedef enum _LinkForce {
LF_NO,
LF_YES
} LinkForce;
typedef enum _LinkType {
LT_HARD = 0,
LT_SOFT
} LinkType;
static int _ln_error(char const * message, int ret);
static int _ln_is_directory(char * dest);
static int _ln_single(LinkForce lf, LinkType lt, char const * src,
char const * dest);
static int _ln_multiple(LinkForce lf, LinkType lt, int argc, char * argv[]);
static int _ln(LinkForce lf, LinkType lt, int argc, char * argv[])
{
if(argc == 2 && !_ln_is_directory(argv[1]))
return _ln_single(lf, lt, argv[0], argv[1]);
return _ln_multiple(lf, lt, argc, argv);
}
static int _ln_error(char const * message, int ret)
{
fputs("ln: ", stderr);
perror(message);
return ret;
}
static int _ln_is_directory(char * dest)
{
struct stat buf;
if(stat(dest, &buf) == -1 || !S_ISDIR(buf.st_mode))
return 0;
return 1;
}
static int _ln_single(LinkForce lf, LinkType lt, char const * src,
char const * dest)
{
if(lf == LF_YES)
unlink(dest);
if((lt == LT_HARD ? link(src, dest) : symlink(src, dest)) == -1)
return _ln_error(dest, 1);
return 0;
}
static int _ln_multiple(LinkForce lf, LinkType lt, int argc, char * argv[])
{
int i;
ssize_t len;
char * dest = NULL;
char * p;
for(i = 0; i < argc - 1; i++)
{
len = strlen(argv[argc - 1]) + strlen(argv[i]) + 2;
if((p = realloc(dest, len)) == NULL)
{
_ln_error(argv[i], 0);
continue;
}
dest = p;
snprintf(dest, len, "%s/%s", argv[argc - 1], argv[i]);
_ln_single(lf, lt, argv[i], dest);
}
free(dest);
return 0;
}
static int _usage(void)
{
fputs("Usage: ln [-fs] source_file target_file\n\
ln [-fs] source_file ... target_dir\n\
-f Force existing destination pathnames to be removed\n\
-s Create symbolic links instead of hard links\n", stderr);
return 1;
}
int main(int argc, char * argv[])
{
LinkForce flgf = LF_NO;
LinkType flgs = LT_HARD;
int o;
while((o = getopt(argc, argv, "fs")) != -1)
switch(o)
{
case 'f':
flgf = LF_YES;
break;
case 's':
flgs = LT_SOFT;
break;
default:
return _usage();
}
if(argc - optind <= 1)
return _usage();
return _ln(flgf, flgs, argc - optind, &argv[optind]);
}