-
Notifications
You must be signed in to change notification settings - Fork 44
/
airscan-os.c
160 lines (137 loc) · 3.86 KB
/
airscan-os.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/* AirScan (a.k.a. eSCL) backend for SANE
*
* Copyright (C) 2019 and up by Alexander Pevzner ([email protected])
* See LICENSE for license terms and conditions
*
* OS Facilities
*/
#include "airscan.h"
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#if defined(__OpenBSD__) || defined(__FreeBSD__)
# include <sys/types.h>
# include <sys/sysctl.h>
#endif
/* Static variables */
static pthread_once_t os_homedir_once = PTHREAD_ONCE_INIT;
static char os_homedir_buf[PATH_MAX];
static pthread_once_t os_progname_once = PTHREAD_ONCE_INIT;
static char os_progname_buf[PATH_MAX];
/* Initialize os_homedir_buf. Called once, on demand
*/
static void
os_homedir_init (void)
{
const char *s = getenv("HOME");
struct passwd pwd, *result;
char buf[16384];
/* Try $HOME first, so user can override it's home directory */
if (s != NULL && s[0] && strlen(s) < sizeof(os_homedir_buf)) {
strcpy(os_homedir_buf, s);
return;
}
/* Now try getpwuid_r */
getpwuid_r(getuid(), &pwd, buf, sizeof(buf), &result);
if (result == NULL) {
return;
}
if (result->pw_dir[0] && strlen(result->pw_dir) < sizeof(os_homedir_buf)) {
strcpy(os_homedir_buf, result->pw_dir);
}
}
/* Get user's home directory.
* There is no need to free the returned string
*
* May return NULL in a case of error
*/
const char *
os_homedir (void)
{
pthread_once(&os_homedir_once, os_homedir_init);
return os_homedir_buf[0] ? os_homedir_buf : NULL;
}
/* Initialize os_progname_buf. Called once, on demand
*/
static void
os_progname_init (void)
{
/* Obtain path to the executable */
#ifdef OS_HAVE_LINUX_PROCFS
ssize_t rc;
memset(os_progname_buf, 0, sizeof(os_progname_buf));
rc = readlink("/proc/self/exe", os_progname_buf,
sizeof(os_progname_buf) - 1);
if (rc < 0) {
return;
}
#elif defined(__OpenBSD__)
struct kinfo_proc kp;
const int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid(),
sizeof(struct kinfo_proc), 1};
size_t len = sizeof(kp);
int rc = sysctl(mib, 6, &kp, &len, NULL, 0);
if (rc == -1) {
return;
}
memmove(os_progname_buf, kp.p_comm, KI_MAXCOMLEN);
#elif defined(__FreeBSD__)
const int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
size_t len = sizeof(os_progname_buf);
int rc = sysctl(mib, 4, os_progname_buf, &len, NULL, 0);
if (rc < 0) {
os_progname_buf[0] = '\0'; /* Just a paranoia */
}
#else
/* This is nice to have but not critical. The caller already has
to handle os_progname returning NULL. The error is left as a
reminder for anyone porting this. */
# error FIX ME
#endif
/* Strip the directory, leave only the file name */
char *s = strrchr(os_progname_buf, '/');
if (s != NULL) {
memmove(os_progname_buf, s+1, strlen(s+1) + 1);
}
}
/* Get base name of the calling program.
* There is no need to free the returned string
*
* May return NULL in a case of error
*/
const char*
os_progname (void)
{
pthread_once(&os_progname_once, os_progname_init);
return os_progname_buf[0] ? os_progname_buf : NULL;
}
/* Make directory with parents
*/
int
os_mkdir (const char *path, mode_t mode)
{
size_t len = strlen(path);
char *p = alloca(len + 1), *s;
if (len == 0) {
errno = EINVAL;
return -1;
}
strcpy(p, path);
for (s = strchr(p + 1, '/'); s != NULL; s = strchr(s + 1, '/')) {
*s = '\0';
/* Note, we have nothing to do with errors in creation of
* intermediate directories, but status of creation of the
* final directory in the path is checked below
*/
(void) mkdir(p, mode);
*s = '/';
}
return mkdir(p, mode);
}
/* vim:ts=8:sw=4:et
*/