300fc543762140ba69065a4f3518e4aab9efda3b
[sgt/putty] / unix / uxmisc.c
1 /*
2 * PuTTY miscellaneous Unix stuff
3 */
4
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <assert.h>
9 #include <unistd.h>
10 #include <time.h>
11 #include <sys/time.h>
12 #include <sys/types.h>
13 #include <pwd.h>
14
15 #include "putty.h"
16
17 unsigned long getticks(void)
18 {
19 /*
20 * We want to use milliseconds rather than the microseconds or
21 * nanoseconds given by the underlying clock functions, because we
22 * need a decent number of them to fit into a 32-bit word so it
23 * can be used for keepalives.
24 */
25 #if defined HAVE_CLOCK_GETTIME && defined HAVE_DECL_CLOCK_MONOTONIC
26 {
27 /* Use CLOCK_MONOTONIC if available, so as to be unconfused if
28 * the system clock changes. */
29 struct timespec ts;
30 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
31 return ts.tv_sec * TICKSPERSEC +
32 ts.tv_nsec / (1000000000 / TICKSPERSEC);
33 }
34 #endif
35 {
36 struct timeval tv;
37 gettimeofday(&tv, NULL);
38 return tv.tv_sec * TICKSPERSEC + tv.tv_usec / (1000000 / TICKSPERSEC);
39 }
40 }
41
42 Filename *filename_from_str(const char *str)
43 {
44 Filename *ret = snew(Filename);
45 ret->path = dupstr(str);
46 return ret;
47 }
48
49 Filename *filename_copy(const Filename *fn)
50 {
51 return filename_from_str(fn->path);
52 }
53
54 const char *filename_to_str(const Filename *fn)
55 {
56 return fn->path;
57 }
58
59 int filename_equal(const Filename *f1, const Filename *f2)
60 {
61 return !strcmp(f1->path, f2->path);
62 }
63
64 int filename_is_null(const Filename *fn)
65 {
66 return !fn->path[0];
67 }
68
69 void filename_free(Filename *fn)
70 {
71 sfree(fn->path);
72 sfree(fn);
73 }
74
75 int filename_serialise(const Filename *f, void *vdata)
76 {
77 char *data = (char *)vdata;
78 int len = strlen(f->path) + 1; /* include trailing NUL */
79 if (data) {
80 strcpy(data, f->path);
81 }
82 return len;
83 }
84 Filename *filename_deserialise(void *vdata, int maxsize, int *used)
85 {
86 char *data = (char *)vdata;
87 char *end;
88 end = memchr(data, '\0', maxsize);
89 if (!end)
90 return NULL;
91 end++;
92 *used = end - data;
93 return filename_from_str(data);
94 }
95
96 #ifdef DEBUG
97 static FILE *debug_fp = NULL;
98
99 void dputs(char *buf)
100 {
101 if (!debug_fp) {
102 debug_fp = fopen("debug.log", "w");
103 }
104
105 write(1, buf, strlen(buf));
106
107 fputs(buf, debug_fp);
108 fflush(debug_fp);
109 }
110 #endif
111
112 char *get_username(void)
113 {
114 struct passwd *p;
115 uid_t uid = getuid();
116 char *user, *ret = NULL;
117
118 /*
119 * First, find who we think we are using getlogin. If this
120 * agrees with our uid, we'll go along with it. This should
121 * allow sharing of uids between several login names whilst
122 * coping correctly with people who have su'ed.
123 */
124 user = getlogin();
125 setpwent();
126 if (user)
127 p = getpwnam(user);
128 else
129 p = NULL;
130 if (p && p->pw_uid == uid) {
131 /*
132 * The result of getlogin() really does correspond to
133 * our uid. Fine.
134 */
135 ret = user;
136 } else {
137 /*
138 * If that didn't work, for whatever reason, we'll do
139 * the simpler version: look up our uid in the password
140 * file and map it straight to a name.
141 */
142 p = getpwuid(uid);
143 if (!p)
144 return NULL;
145 ret = p->pw_name;
146 }
147 endpwent();
148
149 return dupstr(ret);
150 }
151
152 /*
153 * Display the fingerprints of the PGP Master Keys to the user.
154 * (This is here rather than in uxcons because it's appropriate even for
155 * Unix GUI apps.)
156 */
157 void pgp_fingerprints(void)
158 {
159 fputs("These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
160 "be used to establish a trust path from this executable to another\n"
161 "one. See the manual for more information.\n"
162 "(Note: these fingerprints have nothing to do with SSH!)\n"
163 "\n"
164 "PuTTY Master Key (RSA), 1024-bit:\n"
165 " " PGP_RSA_MASTER_KEY_FP "\n"
166 "PuTTY Master Key (DSA), 1024-bit:\n"
167 " " PGP_DSA_MASTER_KEY_FP "\n", stdout);
168 }
169
170 /*
171 * Set FD_CLOEXEC on a file descriptor
172 */
173 int cloexec(int fd) {
174 int fdflags;
175
176 fdflags = fcntl(fd, F_GETFD);
177 if (fdflags == -1) return -1;
178 return fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC);
179 }
180
181 FILE *f_open(const Filename *filename, char const *mode, int is_private)
182 {
183 if (!is_private) {
184 return fopen(filename->path, mode);
185 } else {
186 int fd;
187 assert(mode[0] == 'w'); /* is_private is meaningless for read,
188 and tricky for append */
189 fd = open(filename->path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
190 if (fd < 0)
191 return NULL;
192 return fdopen(fd, mode);
193 }
194 }
195
196 FontSpec *fontspec_new(const char *name)
197 {
198 FontSpec *f = snew(FontSpec);
199 f->name = dupstr(name);
200 return f;
201 }
202 FontSpec *fontspec_copy(const FontSpec *f)
203 {
204 return fontspec_new(f->name);
205 }
206 void fontspec_free(FontSpec *f)
207 {
208 sfree(f->name);
209 sfree(f);
210 }
211 int fontspec_serialise(FontSpec *f, void *data)
212 {
213 int len = strlen(f->name);
214 if (data)
215 strcpy(data, f->name);
216 return len + 1; /* include trailing NUL */
217 }
218 FontSpec *fontspec_deserialise(void *vdata, int maxsize, int *used)
219 {
220 char *data = (char *)vdata;
221 char *end = memchr(data, '\0', maxsize);
222 if (!end)
223 return NULL;
224 *used = end - data + 1;
225 return fontspec_new(data);
226 }